Stream API is a newly added feature to the Collections API in Java Eight. A stream represents a sequence of elements and supports different operations (Filter, Sort, Map, and Collect) from a collection. We can combine these operations to form a pipeline to query the data, as shown in the below diagram:
An Example of How Java Streams Work:
The simplest way to think of Java streams is to imagine a list of objects disconnected from each other, entering a pipeline one at a time. You can control how many of these objects are entering the pipeline, what you do to them inside it, and how you catch them as they exit the pipeline.
We can obtain a stream from a collection using the .stream() method. For example, we have a dropdown of languages in the header section and want to print the dropdown list using both for loop & Stream API.
Let’s explain this with an array List example:
List<String>languages = new ArrayList <String>();
languages.add(“English”);
languages.add(“German”);
languages.add(“French”);
If we need to print the list of members,
Using For loop:
For(String language:languages)
{
System.out.println(language);
}
Usage of Stream API Methods:
Using stream API, we can obtain the stream by calling the .stream() method on the languages array list and printing it in the following way:
Languages.stream().forEach(System.out::println)
After getting the stream, we called the forEach() method & pass the action we wanted to take on each Element, then printed the member value on the console using the System.out.println method.
After getting a stream from a collection, we can use that stream to process the collection’s elements.
stream.Filter():
The filter() method is used to filter a stream. Let’s use the above stream example to filter out the languages list based on specific criteria, i.e., items starting with ‘E.’
stream.filter(item->item.startsWith(“E”));
The filter() method takes a predicate as a parameter. The predicate interface contains a function called boolean test(T t) that takes a single parameter and returns a Boolean. In this example, we passed lambda expression (item->item.startsWith(“E”)) to the test() function.
When the filter() method is called on a stream, the filter passed as a parameter to the filter() function is stored internally.
stream.sort():
We can sort a stream by calling the sort() method. Let’s use the sort() method on the above languages list, as shown in the following code:
languages.stream().sorted().forEach(System.out::println);
The above method would help sort the elements in alphabetical order.
stream.map():
Stream provides a map() method to map the elements of a stream into another new object. Let’s use the previous example and convert the elements of the languages list to uppercase, as shown below:
language.stream().map(item->item.uppercase().forEach(System.out::println));
This will map all the elements that are strings in the language collection to their uppercase equivalents.
stream.collect():
Stream API provides a collect() method for processing on the stream interface. When the collect() method is invoked, filtering and mapping will occur, and the object obtained from those actions will be collected. Let’s take the previous example and obtain a new list of languages in uppercase, as shown in the below example:
List<String>
case language = languages.stream().map(item>item.toUpperCase()).collect(collectors.toList()));
System.out.println(ucaselanguage);
First, it creates a stream, adds a map to convert the strings to uppercase, and collects all objects in a new list.
stream.min() & max():
The Stream API provides the min() and max() methods to find the min & max values in streams. These methods are used to find min & max values in different streams like streams of chars, strings, dates, etc. We must change the parameter we pass in this method based on the stream type.
Example:
max(Comparator. comparing (Integer::value of)): To get the max value from a stream of numbers
Here you can see we have used Comparator. You are comparing() method to compare elements of the stream, and this same method is used for comparing elements of all types of streams, such as stream of chars, Strings, etc.
Example:
//Getting max number
Integer maximum = Stream.of(10,13,4,9,2,100).max(Comparator.comparing(Integer::valueOf)).get();
//Getting min number
//getting max number
Integer minimum = Stream.of(10,13,4,9,2,100).min(Comparator.comparing(Integer::valueOf)).get();
System.out.println(“Max number is: ”+maximum);
System.out.println(“Min number is: ”+minimum);
stream.count():
In Stream API, the Count method returns the number of elements in the stream after filtering. So, let’s take the previous example to get the count of languages starting with ‘G.’
long count = languages.stream().filter(item->item.getName().startsWith(‘G’)).count();
count() method returns a long, which is the count of elements matching the filter criteria.
Usage of Stream API in Selenium WebDriver:
Example-1
Filtering and counting WebElements:
List<WebElement>links = driver.find elements(By.tagName("a"));
System.out.println(links.size());
//Printing linkTexts using for..each loop(without Java8)
for (WebElement link : links) {
System.out.println(link.getText());
}
//Printing linkTexts using lambda expression(with Java8 functions)
links.forEach(link -> System.out.println(link.getText()));
//Processing elements using stream -> filter
long workingLinks=links.stream().filter(link->link.getAttribute("href")!=null).count();
System.out.println("Working link:"+workingLinks);
In the preceding code,
- We are finding several links without lambda expression & with lambda expression(Java 8 feature)
- Then print LinkText from all the links
- Using the stream, filter & count feature from java8, check how many links do not have a href attribute (i.e., broken links).
Example-2
List<WebElement>product_items=driver.findElements(By.xpath("//h2[@class='product-title']"));
//Capturing all the product titles in to a list(using stream, lambda, map & collect function)(Orginal List)
List<String>beforesort=product_items.stream().map(item>item.getText()).collect(Collectors.toList());
//Sort products (using stream, lambda, map, sorted & collect function), then capture in into another list(Sorted list)
List<String>aftersort=product_items.stream().map(item>item.getText()).sorted().collect(Collectors.toList());
System.out.println(beforesort);
System.out.println(aftersort);
//Compare Orginal List with sorted List
if (beforesort.equals(aftersort))
System.out.println("products displayed in Sorted Order");
Else
System.out.println("products displayed in NOT Sorted Order");
Advantages of Stream API:
- Stream conveys elements from a source, such as a data structure, an array, a generator function, or an I/O channel, through a pipeline of computational operations.
- It’s functional in nature, and an operation on a stream produces a result but doesn’t modify its source. For example, when we are filtering a stream obtained from a collection, it has a new Stream without the filtered elements.
- Consumable: Elements of a stream are visited once during the life of a stream. Like an Iterator, a new stream should be created to revisit the same source elements.
Conclusion:
Here we learned how to use Stream API and Lambda functions in selenium WebDriver code, and it helps us to write code in a functional programming style, which is more readable in nature. Streams are also helpful in working with the list of WebElements, where we can easily collect & filter data with a stream.