Example: create stream from List by calling stream() method
List<String> myList =
Arrays.asList("Hello", "World", "Java8", "Stream");
myList
.stream()
.filter(s -> s.startsWith("Java"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
//output
// Java8
Stream operations are either intermediate or terminal.
Intermediate operations return a stream , can be chained for multiple intermediate operations.
Terminal operations are either void or return a non-stream result.
In the above example filter, map and sorted are intermediate operations whereas forEach is a terminal operation. .
Sequential Stream
Sequential stream is created by calling stream() methodArrays.asList("One", "Two", "Three")
.stream()
.findFirst()
.ifPresent(System.out::println); // One
Use Stream.of() to create a stream from object references.
Stream.of("One", "Two", "Three")
.findFirst()
.ifPresent(System.out::println); // One
Java 8 gives special kinds of streams for working with the primitive data types int, long and double.
IntStream, LongStream and DoubleStream.
Example :
IntStream.range(1, 4)
.forEach(System.out::println);
// 1
// 2
// 3
Primitive streams use specialized lambda expressions, e.g. IntFunction instead of Function or IntPredicate instead of Predicate.
Primitive streams also support the additional terminal aggregate operations sum() and average():
Arrays.stream(new int[] {1, 2, 3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println); // 5.0
A regular object stream can be transfored to a primitive stream or vice versa.
Object streams support the special mapping operations mapToInt(), mapToLong() and mapToDouble:
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.max()
.ifPresent(System.out::println); // 3
Primitive streams can be transformed to object streams via mapToObj():
IntStream.range(1, 4)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a3
Intermediate and Terminal operations
Intermediate operations on stream are lazy , which means intermediate operations are executed only if the stream method chains ends with Action or terminal function
Stream.of("Hello", "World", "Java8", "Stream");
.filter(s -> {
System.out.println("filter: " + s);
return true;
});
//no output
No terminal operation present, means no execution.
Lets add forEach terminal operation and run again
Stream.of("Hello", "World", "Java8", "Stream");
.filter(s -> {
return true;
}).forEach(System.out::println);
Executing this code snippet results in the desired output on the console:
//ouput
Hello
World
Java8
Stream
Collectors
Collect is an extremely useful terminal operation to transform the elements of the stream into a different kind of result, e.g. a List, Set or Map// example return result as List
List<String> listOfString =
Stream.of("Hello", "World", "Java8", "Stream");
.filter(s -> {
System.out.println("filter: " + s);
return true;
})
.collect(Collectors.toList());
// example join string
List<String> list = Arrays.asList("java", "python", "nodejs", "ruby");
String result = list.stream().map(x -> x).collect(Collectors.joining(" | "));
//java | python | nodejs | ruby
FlatMap
FlatMap transforms each element of the stream into a stream of other objects. So each object will be transformed into zero, one or multiple other objects backed by streams.Lets see an example
class Student{
String name;
List<Section> sections = new ArrayList<>();
Student(String name) {
this.name = name;
}
}
class Section{
String name;
Section(String name) {
this.name = name;
}
}
// create list of students List<Student> students = new ArrayList<>();
// create students
IntStream
.range(1, 4)
.forEach(i -> students .add(new Student("Student" + i)));
// create bars
students .forEach(s ->
IntStream
.range(1, 3)
.forEach(i -> s.sections.add(new Section("Section" + i + " <- " + s.name))));
///
students.stream()
.flatMap(s -> s.sections.stream())
.forEach(sc -> System.out.println(sc.name));
// Student1 <- Section1
// Student2 <- Section1
// Student3 <- Section1
// Student1 <- Section2
// Student2 <- Section2
// Student3 <- Section2
Reduce
The reduction operation combines all elements of the stream into a single result.persons
.stream()
.reduce((p1, p2) -> p1.age > p2.age ? p1 : p2)
.ifPresent(System.out::println);
Parallel Streams
Streams can be executed in parallel to increase runtime performance on large amount of input elements.
Parallel streams use a common ForkJoinPool available via the static ForkJoinPool.commonPool() method.
The size of the underlying thread-pool threads depending on the amount of available physical CPU cores
ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism());
Parallelism can be set using following jvm parameter
-Djava.util.concurrent.ForkJoinPool.common.parallelism=5
Collections support the method parallelStream() to create a parallel stream of elements. Alternatively you can call the intermediate method parallel() on a given stream to convert a sequential stream to a parallel counterpart.
In order to understate the parallel execution behavior of a parallel stream the next example prints information about the current thread to sout:
Arrays.asList("a1", "a2", "b1", "c2", "c1")
.parallelStream()
.filter(s -> {
System.out.format("filter: %s [%s]\n",
s, Thread.currentThread().getName());
return true;
})
.map(s -> {
System.out.format("map: %s [%s]\n",
s, Thread.currentThread().getName());
return s.toUpperCase();
})
.forEach(s -> System.out.format("forEach: %s [%s]\n",
s, Thread.currentThread().getName()));
Here is the output
filter: b1 [main]
filter: a2 [ForkJoinPool.commonPool-worker-1]
map: a2 [ForkJoinPool.commonPool-worker-1]
filter: c2 [ForkJoinPool.commonPool-worker-3]
map: c2 [ForkJoinPool.commonPool-worker-3]
filter: c1 [ForkJoinPool.commonPool-worker-2]
map: c1 [ForkJoinPool.commonPool-worker-2]
forEach: C2 [ForkJoinPool.commonPool-worker-3]
forEach: A2 [ForkJoinPool.commonPool-worker-1]
map: b1 [main]
forEach: B1 [main]
filter: a1 [ForkJoinPool.commonPool-worker-3]
map: a1 [ForkJoinPool.commonPool-worker-3]
forEach: A1 [ForkJoinPool.commonPool-worker-3]
forEach: C1 [ForkJoinPool.commonPool-worker-2]
Parallel stream operations share the same JVM-wide common ForkJoinPool.
Think before using it , cz it may slow down other parts of your application which rely heavily on parallel streams.
Detail about stream api can be found at https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
No comments:
Post a Comment