Uses of Stream in Java 8

Posted By : Ranjan Mondal | 30-Apr-2018
 

Introduction : Streams represent a sequence of items or elements and have different operations to perform complex and simple computations upon those elements.

Streams operations are
intermediate: always returns stream object so you can chain multiple operations. eg. forEach, collect
terminal: returns a void or non-stream result. eg filter, sorted, map.

Most stream operation accepts an instance of the Functional interface to do its operations. We can use lambda expression for instance of the functional interface.

Lambda expression is non-interfering and stateless.
non-interfering: it does not modify underlying data source of the stream like removing or adding elements to collections.
stateless: During execution, lambda does not depend on any mutable variables outside the scope.

We can convert regular Object Stream into IntStream, LongSteam and DoubleStream using mapToInt(), mapToLong() and mapToDouble().

         List<string> codeList =
                Arrays.asList("a1", "a2", "b1", "c2", "c1");

        codeList.stream()
                .map(ele -> ele.substring(1))
                .mapToInt(Integer::parseInt)
                .forEach(System.out::println);

output: 1,2,1,2,1 

You can convert primitive streams to object steams as well.

         IntStream.range(1,5)
                .mapToObj(ele -> ele + "- object")
                .forEach(System.out::println);
        

Collect is a terminal operation which transforms a sequence of elements into Collections. eg List, Set or Map).

        List<person> persons =
                Arrays.asList(
                        new Person("Max", "Mueler", 18),
                        new Person("Peter","Parker", 23),
                        new Person("Pamela", "Ferguson", 23),
                        new Person("David", "James Anderson", 12));

        persons.stream().filter(ele -> ele.getAge() == 23)
                .collect(Collectors.toList()).stream().forEach(System.out::println);

output: Peter Parker, 23
Pamela Ferguson, 23

You can use groupingBy() for group element on certain conditions.

        Age : 18, Person [Max Mueler, 18]
Age : 23, Person [Peter Parker, 23, Pamela Ferguson, 23]
Age : 12, Person [David James Anderson, 12]

        

To get average of age of all elements.

        Double averageAge  = persons.stream().collect(Collectors.averagingInt(p -> p.age));
        System.out.println("average Age : " + averageAge);
output :average Age : 19.0

Optional<person> person = persons.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2);
        if(person.isPresent()){
            System.out.println("Max age : " + person.get());
        }

        Double maxAge = persons.stream().mapToDouble(ele -> ele.getAge()).reduce(0,(max, ele) -> {
            return max > ele ? max : ele;
        });

        System.out.println("Max age : " + maxAge);

output: 
Max age : Pamela Ferguson, 23
Max age : 23.0
  

Reduce() combines all elements of stream into single results.

        Double sumOfAges = persons.stream()
                .mapToDouble(person -> person.getAge())
                .reduce(0, (sum, age) -> sum + age);
        System.out.println("Sum of ages : " + sumOfAges);
output: Sum of ages : 76.0   
        

To convert Stream to Map and also take care of duplicate entries.

        Map<string, integer> map = persons.stream().collect(Collectors.toMap(ele -> ele.getFirstName(), ele-> ele.getAge(),
               (oldValue, newValue) -> newValue));
       map.forEach((firstName, age) -> System.out.println("Name " + firstName + ", age " +age));

output:
Name Pamela, age 23
Name Max, age 23
Name David, age 12
Some examples are:

Stream<T> distinct(). Returns a stream consisting of the distinct elements.

         Stream stream = Stream.of("ranjan", "mondal","ranjan", "mondal", "rohit");
        stream.distinct().forEach(e -> System.out.println(e));
output : 
ranjan
mondal
rohit
        

Stream<T> limit(long maxSize). Returns a stream truncated to be no longer than maxSize in length.

        Stream stream = Stream.of("ranjan", "mondal","ranjan", "mondal", "rohit");
        stream.limit(2).forEach(e -> System.out.println(e));
output: 
ranjan
mondal
        

 

Stream<T> skip(long n). Returns a stream with the remaining elements of this stream after discarding the first n elements.

          Stream stream = Stream.of("ranjan", "mondal","ranjan", "mondal", "rohit");
        stream.skip(4).forEach(e -> System.out.println(e));
output: rohit
        

Terminal Operations

You can also easily identify terminal operations because they always return something other than a stream.

After the terminal operation is performed, the stream pipeline is consumed and can't be used anymore. For example:

        Stream stream = Stream.of(1,2,3,4,5);
        System.out.println(stream.count());
        System.out.println(stream.findFirst());

output : 5
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed  
        

Using filter to filter out unwanted elements from stream.

        Stream<String> stream = Stream.of("Java", null, "", "scala");
        stream.filter(e -> e != null)
                .filter(e -> !e.isEmpty())
                .forEach(System.out::println);
output:
Java
scala

Data Search

Searching is a common operation for when you have a set of data.

The Stream API has two types of operation for searching.

Methods starting with Find:

         Optional findFirst()
Stream stream = Stream.of("Java", null, "", "scala");

        Optional<String> first = stream.filter(e -> e != null)
                .filter(e -> !e.isEmpty())
                .findAny();
        System.out.println(first);

output:
Optional[Java]

While working with parallel streams, it's harder to find the first element. In this case, it's better to use findAny() if you don't really mind which element is returned.

The *Match methods.

anyMatch() returns true if any of the elements in a stream matches the given predicate:

           Stream<Integer> stream = Stream.of(1,2,3,4,4,5,7,8);
        boolean result = stream
                .anyMatch(e -> e % 2 == 0);
        System.out.println(result);
output: true
     
        

 

If the sequence is found to be empty or if there's no matching element, this method returns false:

 

About Author

Author Image
Ranjan Mondal

Ranjan is a bright Web App Developer, and has good knowledge of Core java, Spring and hibernate.

Request for Proposal

Name is required

Comment is required

Sending message..