Advanced   Java   Services IntStreams Back Next Up Home


IntStreams

Im folgenden werden eine Reihe von Beispielen für IntStreams zusammengestellt.


Erzeugen von IntStreams

range() , rangeClosed()
IntStream.range(0, 12).forEach(System.out::println);
// 0 1 2 3 4 5 6 7 8 9 10 11
//Endwert ist nicht dabei
IntStream.rangeClosed(0, 12).forEach(System.out::println);
// 0 1 2 3 4 5 6 7 8 9 10 11 12
//Endwert ist dabei

Aus einer Folge von Literalen
// aus einer Folge von Literalen
IntStream.of(0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274 ).forEach(System.out::println);

Aus einem Array
// aus einem Array mit Arrays.stream
int[] intArr = { 1, 1, 2, 3, 5, 8, 13};
Arrays.stream(intArr).forEach(System.out::println);

generate()

generate() erzeugt einen quasi endlosen Stream, der mit limit() beschränkt wird.

IntSupplier supp = () ->  (int)Math.floor(Math.random()*100) ;
IntStream.generate(supp).limit(10).forEach(System.out::println);

iterate()

iterate() erzeugt einen quasi endlosen Stream, der mit limit() beschränkt wird.

// Erzeugen von Potenzen von 2
IntStream.iterate(1, i -> 2*i).limit(11).forEach(System.out::println);
// Erzeugen ungerder Zahlen
IntStream.iterate(1, i -> i+2).limit(6).forEach(System.out::println);

Verwendung von Methoden von IntStream

average() , count() , max() , min() , sum()
int[] intArr = { 1, 1, 2, 3, 5, 8, 13};
OptionalDouble od = Arrays.stream(intArr).average();
if (od.isPresent()) System.out.println(od.getAsDouble());

long count = Arrays.stream(intArr).count();
System.out.println(count);

OptionalInt oiMax = Arrays.stream(intArr).max();
if(oiMax.isPresent()) System.out.println(oiMax.getAsInt());

OptionalInt oiMin = Arrays.stream(intArr).min();
if(oiMin.isPresent()) System.out.println(oiMin.getAsInt());

int sum = Arrays.stream(intArr).sum();
System.out.println(sum);

concat()
IntStream intStream1 = IntStream.of(0, 2, 4, 6, 8);
IntStream intStream2 = IntStream.of(1, 3, 5, 7, 9);
IntStream concat = IntStream.concat(intStream1, intStream2);
concat.forEach(System.out::println);

findAny() , findFirst()
IntStream fibo2 = Arrays.stream(intArr);
OptionalInt oi2 = fibo2.findFirst();
System.out.println("first = " + oi2.getAsInt());
int[] intArr = {1, 2, 3, 5, 8, 13, 21, 34, 55 };
IntStream fibo = Arrays.stream(intArr);
OptionalInt oi = fibo.findAny();
System.out.println("any   = " + oi.getAsInt());
// liefert meistens auch das erste Element

map(IntUnaryOperator mapper) , mapToDouble(IntToDoubleFunction mapper)

IntStream digits = IntStream.range(1, 10);
digits.map( i -> i*i*i).forEach(System.out::println);
System.out.println();

IntStream netto = IntStream.of(123, 456, 789, 234, 567 );
DoubleStream doubleStream = netto.mapToDouble( i -> 0.19*i );
doubleStream.forEach(System.out::println);

Ausgabe

1
8
27
64
125
216
343
512
729

23.37
86.64
149.91
44.46
107.73

parallel() , forEachOrdered()

forEachOrdered stellt bei parallelen Streams die ursprüngliche Reihenfolge wieder her.

IntConsumer printInt = i -> System.out.print(i + " ");

IntStream digits = IntStream.range(0, 10);
digits.map( i -> i*i).forEach(printInt);
System.out.println();

IntStream digits2 = IntStream.range(0, 10);
digits2.parallel().map( i ->i*i).forEach(printInt);
System.out.println();

IntStream digits3 = IntStream.range(0, 10);
digits3.parallel().map( i -> i*i).forEachOrdered(printInt);
System.out.println();

Ausgabe

0 1 4 9 16 25 36 49 64 81
36 25 4 49 16 64 9 81 1 0
0 1 4 9 16 25 36 49 64 81

distinct(), filter(), sorted()

Straightforward...

IntSupplier supp = () ->  (int)Math.floor(Math.random()*100) ;
IntStream.generate(supp).limit(16).distinct().filter( i -> i%2 == 1).sorted().forEach(printInt);
// 21 33 41 57 59 77 79 83 87
// 9 35 41 47 83 91

peek(IntConsumer action)

peek() ist u.a. dazu verwendet werden um eine Kontrollausgabe zu machen um den Zustand eines Streams auszugeben.

IntSupplier supp = () ->  (int)Math.floor(Math.random()*100) ;
IntStream.generate(supp).limit(12)
                        .peek( i -> System.out.print("("+i+")"))
                        .distinct()
                        .filter( i -> i%2 == 1)
                        .sorted()
                        .forEach(i -> System.out.print("["+i+"]"));

// (88)(89)(91)(82)(26)(52)(5)(95)(66)(83)(19)(65)[5][19][65][83][89][91][95]
// (46)(11)(11)(8)(53)(99)(48)(59)(18)(84)(54)(18)[11][53][59][99]

reduce(IntBinaryOperator op) , reduce(int identity, IntBinaryOperator op)

Der IntBinaryOperator wird wiederholt aufgerufen, wie das folgende Beispiel zeigt

IntStream intStream = IntStream.rangeClosed(1, 10);
// In i entsteht die "Summe", die am Ende zurückgegeben wird
// j durchwandert die Streamelemente
OptionalInt oi = intStream.reduce( (i,j) -> { System.out.println("i="+i+" j="+j);  return i+2*j; } );
if(oi.isPresent()) System.out.println(oi.getAsInt());

Ausgabe

i=1 j=2
i=5 j=3
i=11 j=4
i=19 j=5
i=29 j=6
i=41 j=7
i=55 j=8
i=71 j=9
i=89 j=10
109

In der zweiten Fassung wird der erste Parameter als Startwert verwendet. Der IntBinaryOperator wird wiederholt aufgerufen, wie das folgende Beispiel zeigt

IntStream intStream = IntStream.rangeClosed(1, 10);
// in i entsteht das Ergebnis, das am Ende zurückgegeben wird
int erg = intStream.reduce(0, (i,j) -> { System.out.println("i="+i+" j="+j);  return i+2*j; } );
System.out.println(erg);

Ausgabe

i=0 j=1
i=2 j=2
i=6 j=3
i=12 j=4
i=20 j=5
i=30 j=6
i=42 j=7
i=56 j=8
i=72 j=9
i=90 j=10
110

flatMap(IntFunction<? extends IntStream> mapper)

Das Beispiel erzeugt aus einem IntStream einen zweiten, indem jedes Element aus dem ersten im zweiten Stream dreinal vorhanden ist.

IntConsumer printInt = i -> System.out.print(i + " ");

IntFunction<? extends IntStream> mapper = i -> IntStream.iterate(i, k -> k).limit(3) ;
IntStream sequence = IntStream.rangeClosed(1, 5).flatMap(mapper);
sequence.forEach(printInt);

Ausgabe

1 1 1 2 2 2 3 3 3 4 4 4 5 5 5

collect()

Bei collect() ist es wichtig sich klarzumachen, daß R der Typ ist der zurückgegeben wird. Bei vielen Anwendungen wird der dritte Parameter von collect() nicht verwendet, in diesen Fällen kann einfach null übergeben werden.

<R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)

Prinzip

Der Returntyp R fungiert als ein Art Behälter, in dem die Elemente des Streams landen. Dieser Behälter kann etwa eine Liste sein, die alle Elemente oder ausgewählte Elemente des Streams aufnimmt. Der Behälter kann aber auch nur ein einziges Objekt oder auch ein primitiver Datentyp sein, etwa ein long, das die Summe aller Elemente des Intstreams aufnimmt. Aufgabe des accumulator ist es, die Elemente des Streams in diesen Behälter zu bringen. Der supplier dagegen muß den Behälter bereitstellen. Bei parallelen Streams müssen die beiden Streams wieder zusammengführt werden, diese Aufgabe übernimmt dann der combiner.


IntStream  ->  List<Integer>

Wir bringen eine Reihe von Fibonacci-Zahlen in eine Liste.

IntStream  intStream = IntStream.of(0, 1, 1, 2, 3, 5, 8, 13, 21, 34);

// Parameter 1 von collect: Supplier<R> : erzeugt ein Behälterobjekt, hier eine Liste
Supplier<List<Integer>>  supp = ArrayList::new;

// Parameter 2 von collect: ObjIntConsumer<R> :
// Der ObjIntConsumer bekommt als ersten Parameter das durch den Supplier erzeugte Objekt
// und als zweiten Parameter das zu akkumulierende Objekt aus dem Stream
// hier: erster Parameter die Liste, zweiter Parameter ein int aus dem Stream
// Vorgang: int in die Liste aufnehmen
ObjIntConsumer<List<Integer>>  oic = List::add;  //  void   accept(T t, int value)

// Parameter 3 : BiConsumer<R,R> : void   accept(R t, R u)
// wird hier bei einem NICHT-parallelen streams nicht verwendet, kann dann null sein
List<Integer> intList = intStream.collect(supp, oic, null);
System.out.println(intList);

Ausgabe

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Der parallele Fall

Wir bringen eine Reihe von Fibonacci-Zahlen in eine Liste.

IntStream  intStream = IntStream.of(0, 1, 1, 2, 3, 5, 8, 13, 21, 34);

// Parameter 1 von collect: Supplier<R> : erzeugt ein Behälterobjekt, hier eine Liste
Supplier<List<Integer>>  supp = ArrayList::new;

// Parameter 2 von collect: ObjIntConsumer<R> :
// Der ObjIntConsumer bekommt als ersten Parameter das durch den Supplier erzeugte Objekt
// und als zweiten Parameter das zu akkumulierende Objekt aus dem Stream
// hier: erster Parameter die Liste, zweiter Parameter ein int aus dem Stream
// Vorgang: int in die Liste aufnehmen
ObjIntConsumer<List<Integer>>  oic = List::add;  //  void   accept(T t, int value)

// paralleler Fall ////////////////////////////////////////////
// Parameter 3 : BiConsumer<R,R> : void   accept(R a, R b)
// bekommt als ersten Parameter das vom Supplier erzeugte Objekt
// und als zweiten Parameter ein temporäres Behältertobjekt desselben Typs
// Vorgang: Inhalt des temporären Objekts in das zum ersten Parameter gehörende Objekt bringen
// wird nur im parallen Fall gebraucht,

// Um zu sehen wie die zurückgegebene Liste aufgebaut wird gibt es hier ein "syso".
BiConsumer<List<Integer>,List<Integer>> bicons = (a,b) -> { System.out.println( "a = " + a + "  b = " + b);  a.addAll(b); } ;

// Vorsicht: Es kommt auf die Reihenfolge an: a ist die Liste, die zurückgegeben wird
// kürzer, aber undurchsichtiger:  BiConsumer<List<Integer>,List<Integer>> bicons =  List::addAll ;

List<Integer> intList = intStream.parallel().collect(supp, oic, bicons);
System.out.println(intList);

Ausgabe

a = [5]  b = [8]
a = [21]  b = [34]
a = [13]  b = [21, 34]
a = [5, 8]  b = [13, 21, 34]
a = [2]  b = [3]
a = [1]  b = [2, 3]
a = [0]  b = [1]
a = [0, 1]  b = [1, 2, 3]
a = [0, 1, 1, 2, 3]  b = [5, 8, 13, 21, 34]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

collect() mit Collectors

Mit der Factoryklasse Collectors kann man das Vorgehen deutlich vereinfachen. Diese Hilfsklasse stellt durch statische Methoden fertife Collectoren bereit, die für viele Anwendungen ausreichend sind. Die folgende Beispiele zeigen, wie man einen IntStream in eine Liste oder eine Set verwandeln kann.


IntStream  ->  List<Integer>
IntStream  intStream = IntStream.of(0, 1, 1, 2, 3, 5, 8, 13, 21, 34);
List<Integer> intList = intStream.boxed().collect( Collectors.toList());

oder auch

IntStream  intStream2 = IntStream.of(0, 1, 1, 2, 3, 5, 8, 13, 21, 34);
List<Integer> intList = intStream.mapToObj(Integer::new).collect(Collectors.toList());

IntStream  ->  Set<Integer>
IntStream  intStream = IntStream.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4);
Set<Integer> intSet = intStream.boxed().collect( Collectors.toSet());

oder auch

IntStream  intStream = IntStream.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4);
Set<Integer> intSet = intStream.mapToObj(Integer::new).collect(Collectors.toSet());

































Valid XHTML 1.0 Strict top Back Next Up Home