Un mémo sur l'utilisation de la bibliothèque Google MµG, une bibliothèque utilitaire pour Java 8.
dependencies {
compile 'com.google.mug:mug:1.12'
}
BiStream
Stream
avec clé et valeur.
BiStream
Utilisez la méthode statique de BiStream
.
biStream()
var input = Stream.of( "foo", "bar", "buz" );
var result = BiStream.biStream( input )
.mapValues( e -> e.toUpperCase() )
.toMap();
assertThat( result ).containsExactly( "foo", "FOO", "bar", "BAR", "buz", "BUZ" );
Enveloppez un Stream
normal. Quand on se demande quoi utiliser, il semble que ce soit pour appeler une opération comme mapKeys ()
par la suite.
var input = Stream.of( "foo", "bar", "buz" );
var result = BiStream.biStream( input, Function.identity(), e -> e.toUpperCase() )
.toMap();
assertThat( result ).containsExactly( "foo", "FOO", "bar", "BAR", "buz", "BUZ" );
Une version qui prend une fonction de mappage comme argument.
from()
var input = Map.of( "foo", "123", "bar", "456", "buz", "789" );
var result = BiStream.from( input )
.map( ( i, v ) -> i + ":" + v )
.collect( toList() );
assertThat( result ).containsExactly( "foo:123", "bar:456", "buz:789" );
Créez un BiStream
avec la clé de la carte et la valeur en tant que paire.
indexed()
var input = Stream.of( "foo", "bar", "buz" );
var result = BiStream.indexed( input )
.map( ( i, v ) -> i + ":" + v )
.collect( toList() );
assertThat( result ).containsExactly( "0:foo", "1:bar", "2:buz" );
Ajoutez un index à partir de 0. C'est bien car il est intégré aux API standard de la plupart des langages de programmation. Le type de retour est «BiStream <Integer, V>». Les types primitifs ne sont pas pris en charge comme prévu.
neighbors()
var input = Stream.of( "foo", "bar", "buz" );
var result = BiStream.neighbors( input )
.map( ( i, v ) -> i + ":" + v )
.collect( toList() );
assertThat( result ).containsExactly( "foo:bar", "bar:buz" );
Associez deux valeurs adjacentes.
of()
var result = BiStream.of( "foo", "123", "bar", "456" )
.map( ( i, v ) -> i + ":" + v )
.collect( toList() );
assertThat( result ).containsExactly( "foo:123", "bar:456" );
Similaire au standard JDK ʻof () `.
zip()
var input1 = Stream.of( "foo", "bar", "buz" );
var input2 = Stream.of( "hoge", "piyo", "fuga" );
var result = BiStream.zip( input1, input2 )
.map( ( t, u ) -> t + ":" + u )
.collect( toList() );
assertThat( result ).containsExactly( "foo:hoge", "bar:piyo", "buz:fuga" );
Combinez les deux Stream
s. J'ai toujours fait ça moi-même. Pour être honnête, le niveau que je veux que vous ajoutiez à la bibliothèque standard.
Cependant, notez que si la taille de «Stream» est différente, le reste sera ignoré selon le plus petit.
var input1 = Stream.of( "foo", "bar", "buz" );
var input2 = Stream.of( "hoge", "piyo" );
var result = BiStream.zip( input1, input2 )
.map( ( t, u ) -> t + ":" + u )
.collect( toList() );
assertThat( result ).containsExactly( "foo:hoge", "bar:piyo" );
BiStream
Stream
, des opérations pour des clés et des valeurs telles que filterKeys () ʻet
mapValues ()` ont été ajoutées.append()
var result = BiStream.of( "foo", "123" ).append( "bar", "456" )
.map( ( t, u ) -> t + ":" + u )
.collect( toList() );
assertThat( result ).containsExactly( "foo:123", "bar:456" );
Ajoutez une valeur après.
inverse()
var result = BiStream.of( "foo", "123", "bar", "456" )
.inverse()
.map( ( t, u ) -> t + ":" + u )
.collect( toList() );
assertThat( result ).containsExactly( "123:foo", "456:bar" );
Échangez des valeurs contre des clés. Je veux que vous l'ajoutiez au standard Stream
...
MoreStream
Fournit des extensions introuvables dans JDK ou Guava.
generate()
var result = MoreStreams.generate( 1, n -> n >= 9 ? Stream.empty() : Stream.of( n + 1 ) )
.collect( toList() );
assertThat( result ).containsExactly( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
Une méthode pour générer des flux * finis *. Arrêtez la génération lorsqu'un flux vide est renvoyé. Y a-t-il une utilité pour cela?
flatten()
var input = Stream.of(
Stream.of( "foo", "bar", "buz" ),
Stream.of( "hoge", "piyo", "fuga" )
);
var result = MoreStreams.flatten( input )
.collect( toList() );
assertThat( result ).containsExactly( "foo", "bar", "buz", "hoge", "piyo", "fuga" );
Le même processus devrait être possible avec flatMap
, mais il existe cette méthode car elle ne peut pas gérer des flux infinis à cause d'un bogue Java. Il semble que cela ait été corrigé dans JDK 10.
dice()
var input = Stream.of( "foo", "bar", "buz", "hoge", "piyo" );
var result = MoreStreams.dice( input, 2 )
.collect( toList() );
assertThat( result.size() ).isEqualTo( 3 );
var list1 = result.get( 0 );
assertThat( list1 ).containsExactly( "foo", "bar" );
var list2 = result.get( 1 );
assertThat( list2 ).containsExactly( "buz", "hoge" );
var list3 = result.get( 2 );
assertThat( list3 ).containsExactly( "piyo" );
Listez les Stream
s par taille spécifiée et mettez-les ensemble dans une nouvelleStream <List>
.
Pour les flux séquentiels, il est garanti qu'une liste de la taille spécifiée sera renvoyée sauf à la fin du flux. Non garanti pour les flux parallèles.
En passant, j'ai appris pour la première fois qu'une telle opération s'appelle «dés». En quoi est-ce différent de "window"?
iterateOnce()
var input = Stream.of( "foo", "bar", "buz" );
for ( var e : MoreStreams.iterateOnce( input ) ) {
assertThat( e ).isAnyOf( "foo", "bar", "buz" );
}
Une méthode pour itérer un flux avec une instruction for
. Peut-être que je ne l'utiliserai pas pour le reste de ma vie.
iterateThrough()
expect(() -> {
MoreStreams.iterateThrough( Stream.of( "foo" ), e -> {
throw new Exception( "Checked Exception!" );
});
}).throwsException( e -> {
assertThat( e ).hasMessageThat().isEqualTo( "Checked Exception!" );
});
C'est fondamentalement la même chose que forEach ()
, à la différence que vous pouvez lancer une exception vérifiée.
Retryer
Un processus pour réessayer un processus qui peut échouer. Je pense que c'est pratique, mais la plupart des processus qui nécessitent de nouvelles tentatives sont fournis avec une fonction de nouvelle tentative, donc c'est étonnamment inutile.
Retryer
., ʻifReturns ()
, etc.Delay
. Dans la plupart des cas, vous pouvez utiliser ʻexponentialBackoff () `pour doubler l'intervalle de relance.retryBlockingly ()
, retry ()
, retryAsync ()
.var result = new Retryer()
.upon( RuntimeException.class, Retryer.Delay.ofMillis( 100 ).exponentialBackoff( 2, 2 ) )
.retryBlockingly( this::mayFail );
assertThat( result ).isEqualTo( "success" );
CompletionStage<String> future = new Retryer()
.upon( RuntimeException.class, Retryer.Delay.ofMillis( 100 ).exponentialBackoff( 2, 2 ) )
.retry( this::mayFail, Executors.newSingleThreadScheduledExecutor() );
future.thenAccept( result -> {
assertThat( result ).isEqualTo( "success" );
});
Pour être honnête, l'API asynchrone est subtile.
Maybe
Une classe pour le traitement d'encapsulation qui peut déclencher une exception. Quelque chose comme une version de java.util.Optional
avec la capacité de gérer les exceptions. Est-ce que Try
est relativement proche dans Scala?
Le but principal semble être de gérer facilement les exceptions vérifiées dans les flux.
maybe()
La méthode de base pour créer une instance Maybe
. Accepte diverses interfaces fonctionnelles.
var result = IntStream.range( 1, 10 ).boxed()
.map( Maybe.maybe( e -> {
if ( e <= 5 ) {
return e;
} else {
throw new Exception();
}
} ) )
.map( m -> m.orElse( e -> Integer.valueOf( 0 ) ) )
.collect( toList() );
assertThat( result ).containsExactly( 1, 2, 3, 4, 5, 0, 0, 0, 0 );
La valeur qui a provoqué une exception dans ʻorElse () est convertie en
0`.
expect(() -> {
Maybe.maybe( () -> { throw new RuntimeException( "Unchecked!" );} );
}).throwsException( e -> {
assertThat( e ).hasMessageThat().isEqualTo( "Unchecked!" );
});
Les exceptions non vérifiées sont renvoyées telles quelles. Mise en garde. Ce n'est pas qu'il peut être utilisé pour autre chose que des flux, mais en raison de cette limitation, je pense qu'il est préférable d'utiliser une bibliothèque dédiée.
byValue()
var result = IntStream.range( 1, 10 ).boxed()
.map( Maybe.maybe( e -> {
if ( e <= 5 ) {
return e;
} else {
throw new Exception();
}
} ) )
.filter( Maybe.byValue( n -> n % 2 == 0 ) )
.map( m -> m.orElse( e -> Integer.valueOf( 0 ) ) )
.collect( toList() );
assertThat( result ).containsExactly( 2, 4, 0, 0, 0, 0 );
Puisque filter ()
recevra Maybe
, il existe une méthode pour déballer. Comme vous pouvez le voir, si une exception se produit, elle passe au traitement suivant.
catching()
var result = IntStream.range( 1, 10 ).boxed()
.map( Maybe.maybe( e -> {
if ( e <= 5 ) {
return e;
} else {
throw new Exception();
}
} ) )
.flatMap( m -> m.catching( e -> {} ) )
.collect( toList() );
assertThat( result ).containsExactly( 1, 2, 3, 4, 5 );
À utiliser lorsque vous souhaitez simplement ignorer la valeur.
Funnel
C'est tout un créneau à utiliser, mais cela semble pratique si vous devenez accro.
,
Stream`) en une autre valeurFunnel
var funnel = new Funnel<String>();
var batch = funnel.<String>through( data -> {
assertThat( data ).containsExactly( "batch1", "batch2" );
return data.stream().map( String::toUpperCase ).collect( toList() );
} );
var input = List.of( "local1", "batch1", "local2", "batch2" );
for ( var i : input ) {
if ( i.startsWith( "local" ) ) {
funnel.add( i );
} else {
batch.accept( i );
}
}
var result = funnel.run();
assertThat( result ).containsExactly( "local1", "BATCH1", "local2", "BATCH2" );
Funnel
through ()
pour spécifier le processus de conversion par lots.Funnel.add ()
pour que les valeurs soient traitées individuellement.Funnel.Batch.accept ()
.Funnel.run ()
.Notez que ʻaccept () `a une surcharge qui prend une fonction qui convertit le résultat en argument.
var funnel = new Funnel<String>();
var batch = funnel.<String>through( data -> List.of() );
batch.accept( "batch1" );
expect(() -> {
funnel.run();
}).throwsException( e -> {
assertThat( e ).isInstanceOf( IllegalStateException.class );
});
Évidemment, si la taille de la liste de retour de lots est différente de l'entrée, vous obtiendrez une erreur.
var funnel = new Funnel<String>();
var batch = funnel.<String>through( data -> List.of() );
batch.accept( "batch1" );
expect(() -> {
funnel.run();
}).throwsException( e -> {
assertThat( e ).isInstanceOf( IllegalStateException.class );
});
La commande dépend de l'ordre de traitement par lots. Il est nécessaire de s'assurer que le processus revient dans le même ordre que l'entrée.
var funnel = new Funnel<String>();
var batch = funnel.<String>through( data -> {
var newList = new ArrayList<String>( data );
Collections.reverse( newList );
return newList;
} );
batch.accept( "batch1" );
batch.accept( "batch2" );
var result = funnel.run();
assertThat( result ).containsExactly( "batch2", "batch1" );
Parallelizer
Comme son nom l'indique, parallélisez le traitement.
var input = Stream.of( "foo", "bar", "buz" );
var result = Collections.synchronizedList( new ArrayList<String>() );
new Parallelizer( executor, 3 )
.parallelize( input, result::add );
assertThat( result ).containsExactly( "foo", "bar", "buz" );
Parallelizer
. Les arguments sont ʻExecutorService pour exécuter le processus et le nombre de tâches qui peuvent être exécutées en même temps. Est-ce fondamentalement le même que le nombre de threads dans ʻExecutor Service
?parallelize ()
ou parallelizeUninterruptably ()
. Le premier argument est Stream
ou ʻIterator`, qui sont les données d'entrée, et le deuxième argument est le traitement à effectuer.Le processus est bloqué jusqu'à ce qu'il se termine. Si une exception se produit au milieu, le traitement suivant est interrompu.
Selon README
Parallel streams are for CPU-bound tasks. JDK has built-in magic to optimally use the available cores. Parallelizer is for IO-bound tasks.
Il semble qu'il devrait être utilisé pour l'entrée / la sortie de fichiers, l'appel d'API externe, etc.
BiStream
et MoreStreams
sont pratiquesRecommended Posts