Java Streams API - Process set of elements
A Stream is a series of objects. Source of a stream is an Array, Collection, or Other I/O source. A Stream does not store data, it does only intermediate operations.
It can filter and manipulate the elements of its source. Streams are lazy, the source and intermediate operations do nothing until objects are needed by the terminal operation.
Steams APIs are contained by java.util.stream package.
A water filter is the best example of streams. It processes the water stream. It has multiple filters that work one after another. Filters do purification, reverse osmosis, refinement of water, and produce drinking water. The water filter does not store the water it simply processes the water stream.
Getting Started
1. Create a Stream and print all elements
Let's create a stream from a collection and print all its elements.
The following example creates a Stream from the list collection and prints all elements of the collection using its forEach method.
List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");
//create stream
Stream<String> stream = items.stream();
// Print all elements from stream
stream.forEach(e -> {
System.out.println(e);
});
2. Sort the elements and then print
Stream elements can be sorted using sorted() method.
The following example will create a stream, sort its elements using sorted() method, and then print all elements.
items.stream().sorted().forEach(e -> {
System.out.println(e);
});
3. Convert each element into UPPER CASE then print
Stream elements can be modified using map() method.
The following example will create a stream, convert each element into the upper-case using its map() method, and then print all elements.
items.stream().map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});
4. Filter elements starting with T character and print
Stream elements can be filtered using filter() method.
The following example will filter elements starting with T character using filter() method, convert them into upper case, and then print all elements.
items.stream().filter(e -> e.startsWith("T")).map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});
5. Remove duplicate elements
Stream can remove its duplicate elements using distinct() method.
The following example will filter elements, remove duplicate elements, convert elements to upper case, then print all elements.
items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});
6. All together
The following example will filter elements, remove duplicate elements, convert elements to upper case, sort elements then print all elements.
items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted().forEach(e -> {
System.out.println(e);
});
7. Get collection from Stream
You can get processed elements from Stream into a collection using collect() method.
List<String> l = items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted().collect(Collectors.toList());
Streams vs Collections
Stream and Collection look similar but there are major differences between both:
# | Stream | Collection |
1 | It does not store data | It stores data |
2 | It is read-only | It is read and write both |
3 | It can only be read once | It can be read multiple times |
4 | Elements can not be directly accessed | Elements can be directly accessed i = list.get(0) |
Stream Sources
A stream can be created from arrays, collection, files, and other I/O sources.
1. Collections/ Arrays
List collection, Set collections, and arrays are the common sources of the stream. Map can not be directly used as a source.
String[] a = { "One", "Two", "Three", "Four"};
Stream<String> aStream = Arrays.stream(a);
List<String> l = Arrays.asList("One", "Two", "Three", "Four");
Stream<String> lStream = l.stream();
2. I/O
Data from File and Network can be used as a source to the stream.
Stream<String> fiileData = Files.lines(Path.of("data.txt"));
3. Generators
A Stream can be generated from a function that returns elements for the stream.
For example in this example stream is created from random.nextInt() method. After creating stream we print 5 random numbers.
Random random = new Random();
Stream<Integer> randomNumbers = Stream.generate(random::nextInt);
randomNumbers.limit(5).forEach(System.out::println);
Same can be done by Math.random() method:
Stream<Double> randomNumbers = Stream.generate(Math::random);
Operations
Intermediate operations
An Intermediate Operation transforms one stream into another stream.
Stream methods filter(), map(), distinct(), sorted() etc, perform intermediate operations, and produce another stream.
List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");
Stream<String> stream = items.stream();
items.stream().sorted();
items.stream().map(e -> e.toUpperCase());
items.stream().filter(e -> e.startsWith("T"));
items.stream().distinct();
Intermediate operations are
- map() -It maps a function to a stream and changes elements of the stream
- filter() - It filters element of the stream
- distinct() - It removes duplicate elements from the stream
- sorted() - It sortes elements of the stream
- limit() - It limits and returns the stream according to the given maxSize parameter
- skip() - It skips the given N elements of the stream
Channing intermediate operations
Channing makes Stream powerful. The output of one stream can be an input of another stream it is called Channing.
You can chain multiple operations on stream and produce the desired result using the least code.
For example, the following code applies Channing operations filter, distinct, map, sort, and finally prints all elements of steam in a single line of code.
items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted();
Streams are lazy, which means sources and intermediate operations do not do any work until a terminal is executed.
List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");
Stream<String> stream = items.stream();
items = items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted();
items.forEach(e -> {
System.out.println(e);
});
In the above example filter, distinct, map, and sorted intermediate operations will not be executed until the terminal operation foreach() method is called.
Terminal operations are
- collect() - It converts an stream into collection
- toArray() - It converts a stream into array
- count() -It returns the count of the elements in the stream
- reduce() - It reduces the elements of the stream according to the given identity value.
- min() - It returns the minimum element of the stream according to the given comparator
- max() - It returns the maximum element of the stream according to the given comparator
- anyMatch() - It will return any matched element according to the matched predicate. if the stream is empty then return false
- allMatch() -It will return all the matched elements from a stream. returns true if the stream is empty.
- noneMatch() - It returns the matched elements of the predicate. returns true if the stream is empty
- findAny() - It returns an optional describing some elements of the stream
- findFirst() - It returns the first elements of the stream.
Statistical Operations
You can performer max, min, average statistical operation on integer or double stream.
Classes IntSummaryStatistics and DoubleSummaryStatistics are used to get integer and double value statistical operations.
Methods mapToInt() and mapToDouble() are used to convert stream elements into integers or double values before applying the statistical operations.
Following example will apply statistical operations on marks and account balance:
List<Integer> marks = Arrays.asList(80, 90, 75, 50, 45, 95, 75);
IntSummaryStatistics mStats = marks.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("## Marks statistics ##");
System.out.println("Max Marks: " + mStats.getMax());
System.out.println("Min Matrks: " + mStats.getMin());
System.out.println("Average Marks:" + mStats.getAverage());
System.out.println("Sum : " + mStats.getSum());
System.out.println();
List<Double> accountBalance = Arrays.asList(10000.89, 20000.77, 5000.66, 5500.55, 7000.88, 30000.99, 50000.00);
DoubleSummaryStatistics aStats = accountBalance.stream().mapToDouble(x -> x).summaryStatistics();
System.out.println("## Balance statistics ## ");
System.out.println("Max Balance: " + aStats.getMax());
System.out.println("Min Balance: " + aStats.getMin());
System.out.println("Average Balance:" + aStats.getAverage());
System.out.println("Sum : " + aStats.getSum());
Real-World Example
Let's have Lucky Draw Contest in which contestants have to send SMS. We will select random 3 winners from received SMSs
We will follow the following procedure to select 3 winners:
Let's have data
class Contestant {
public String phone = null;
public Contestant(String n, String p) {
name = n;
phone = p;
}
}
ArrayList<Contestant> list = new ArrayList<Contestant>();
list.add(new Contestant("Ram", "9912345678"));
list.add(new Contestant("Shyam", "9912342222"));
list.add(new Contestant("Ajay", "9912345770"));
list.add(new Contestant("Vijay", "9912345678"));
list.add(new Contestant("Jay", "9912345888"));
list.add(new Contestant("Pappu", "9912345111"));
list.add(new Contestant("InvalidNO", "11"));
1. Get the phone numbers
list.stream().map(e -> e.phone)
2. Get valid phone numbers
list.stream().map(e -> e.phone).filter(e -> e.length() == 10)
3. Remove duplicate phone numbers
list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
4. Shuffle Phone numbers
list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
}))
5. Get 3 Winners
list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
})).limit(3)
6. Display winners
list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
})).limit(3).forEach(e -> System.out.println(e));
WOW !!! Its very simple !!
Example
Q: Write a program to print odd numbers from a list.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class PrintOddNumbers {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 4, 8, 40, 11, 22, 33, 99);
numbers.stream().filter(o -> o % 2 != 0).forEach(System.out::println);
}
}
Find source code at GIT
https://github.com/sunilos/AppliedCoreJava/blob/master/src/com/sunilos/p15streamapi/TestStream.java
More ...
More ...
Also Watch:
► Deploy Angular build on Tomcat or WAMP server - https://www.youtube.com/watch?v=0Gvx7...
► SpringBoot Hibernate Integration - https://www.youtube.com/watch?v=IcSyY...
► Spring Boot – Create RESTful Web Service - https://www.youtube.com/watch?v=QcoB0...
► Angular app using REST API (Part 3) - https://www.youtube.com/watch?v=nthgO...
► Test Public REST API - https://www.youtube.com/watch?v=SUE90...
► Angular First Project (Part-2) - https://www.youtube.com/watch?v=ZySHh...
► Angular First Project (Part-2) - https://www.youtube.com/watch?v=Y9aSJ...
► First Python Program - https://www.youtube.com/watch?v=w_Z6l...
FOLLOW US ON ALL OTHER SOCIAL PLATFORMS!
►YOUTUBE - https://www.youtube.com/sunilos
►LINKEDIN - https://www.linkedin.com/company/rays...
►GITHUB - https://github.com/sunilos
►FACEBOOK - https://www.facebook.com/sunilopensou...
►URL - www.RaysTec.com, www.SunilOS.com
Good examples
ReplyDeleteGood Evening Sir,
ReplyDeleteDoes it create any impact on execution time if we change the sequence of filter->map()->reduce on any raw list(source)?
Thank you for the content sharing sir.
Yes, it will, you should execute operations in the order that number of elements will be reduced for next operation. Elimination filter operations should always come first.
DeleteThank you sir.
DeleteThank you sir
ReplyDeleteThank you because you have been willing to share information with us. We will always appreciate all you have done here because I know you are very concerned with us. Whole house water filtration
ReplyDeleteIt is truly a well-researched content and excellent wording about Bilge Oil Water Separator System. I got so engaged in this material that I could not wait to read it. I am impressed with your work and skill. Thanks.
ReplyDeleteI read your blog in which you shared your best knowledge and great tips about american made water filters. I really need this information. thank you so much for this knowledge. Keep sharing.
ReplyDeleteYou are sharing a piece of pleasant data here. The data you have given is really educational and critical for us. Gratitude for sharing an article like this.Buy sustainable water solutions online
ReplyDelete