Streams API is a new addition in Java 8. Earlier, we used the InputStream or OutputStream to process the streams while handling files and all. The new Streams API provides a set of classes to manipulate the elements in a collection. But, do not confuse IO streams with Java 8 streams; the former deals with bytes while the latter deals with a collection of objects. A stream is not a stored one; rather, it is a computed one. We can perform SQL-like operations on this stream and get the desired result. For those seeking to leverage the power of the Streams API in their projects, our Java development company can provide the expertise and support needed to maximize its potential.
Streams API has following benefits
It provides a set of aggregate functions that simplifies coding. Ex: SQL-like functions such as filter, map, reduce, find, match, and sorted are available for streams, which helps to reduce a lot of code. This capability is particularly useful for those who outsource Java development, as it streamlines coding processes and enhances efficiency.
-
Has parallel processing capability which helps us to leverage the multi-core architecture of the server. This means that we do not need to type multi-threaded code explicitly, the stream will take care of multi-threading.
Let us see how streams can reduce the amount of code while getting the all unique Usernames from the IT department:
Pre Java 8 we do like:
List userNames=new ArrayList (); for(Useruser :userList){ if("IT".equals(user.getDepartment())){ if(!userNames.contains(user.getName())){ userNames.add(user.getName()); } } } But with Streams we can
List userNames = userList.stream() .filter(user->"IT".equals(user.getDepartment())) .map(User::getName) .distinct() .collect(Collectors.toList()); Clean code, right? More readability and less code are other advantages of streams.
Streams API comes with varied benefits and eliminates the necessity of typing multi-threaded code explicitly.Contact us to know more about the benefits and aggregate functions of Streams API and reduce the time you spend typing long coding.
Here, we get a stream from the list of User objects, then operations like filter(), map(), distinct() are applied on that stream. We will see in detail what these operations mean. Finally, the resultant usernames collected in a List and we will return this list. Here we can find the use of lambda expressions [user -> "IT".equals(user.getDepartment())] and method references [User::getName].
Stream Processing
A stream will iterate the elements internally. We can attach listeners to the stream to process each element. These listeners are the call for each element. Audiences are called once for each element in the stream. It refers to as stream processing. The listeners of a stream will form a chain. Each listener in the chain process the element in the stream and then return a new element for the next listener to process.
Terminal and Non-Terminal Operations
The Stream listeners can perform a terminal or a non-terminal operation. A non-terminal stream operation is an operation that adds a listener to the stream which may modify the stream element. While a terminal stream operation, I return a result after stream processing. In the above example map() is a non-terminal operation and collect() is a terminal operation.
Non-Terminal Operations
When we add a non-terminal operation to the stream, it will produce a stream itself. Usually, these operations take a Java Lambda Expression as a parameter. Below are some examples.
-
filter()
The filter() takes a lambda expression the current element will be included in the resulting stream if it satisfies the lambda expression.
Here is an example of calling the Java Stream filter() method, will return all users of 'IT' department.
Stream longStringsStream = userList.stream() .map(User::getName); -
map()
map() method modifies the current element for instance if we need to convert all words in upper case.
Stream wordStream= wordList.stream() .map(String::toUpperCase); -
distinct()
This operation returns only the unique elements in a stream. Below returns the unique usernames.
Stream userNames = userList.stream() .map(User::getName) .distinct();
Terminal Operations
Terminal operations will return a single value. Below are some examples.
-
anyMatch()
The anyMatch() method takes a lambda expression as a parameter and applies it to each element in the stream. If it evaluates to true for any element then, this operation will return a true value.
boolean result= stream.anyMatch((value) -> { return value.startsWith("A"); }); System.out.println(result); -
collect()
This operation will collect the elements to a collection. In the above example, we can see this operation collects usernames in a list.
-
count()
This operation will count the elements in a stream.
long count = userList.stream() .map(User::getName) .count(); -
min() and max()
As the name suggests these operations, will return the minimum and maximum elements.
-
toArray()
This operation will return an array out of the stream elements.
Conclusion:
In this tutorial, we have seen the stream API in Java. The streams API provides many methods for processing the collection of objects. This help to reduce the amount of code and lambda expressions can use along with the streams. Thus, streams provide a functional approach for processing the collection elements. Java Developers India can use the built-in functionalities in this API for processing the collections.