Streams

  1. Intermediate Operations returns Stream as output. methods like map(), sorted(), distinct() would return stream as output
  2. Terminal Operations returns something other than Stream. Collect() returns collection. Reduce() returns one element

Converting list to a stream

List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
//Convert list to stream
Stream objStream = arrNumbers.stream();

//Static Method Reference
objStream.forEach(System.out::println);

Filter

  1. Filter takes a predicate as argument. Predicate returns boolean. The Output of Filter is a Stream
  2. Predicate object which is technically a function to convert an object to boolean. We pass an object and it will return true or false.
  3. filter() method is lazy like map, it wont be evaluated until you call a reduction method, like collect
List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
List<String> arrSkills = List.of("Spring Boot", "Spring Security", "Java 8", "Microservices", "Spring MVC");

//Printing Even Numbers
System.out.println("------Even Numbers-------");
arrNumbers.stream().filter(FilterEgs::isEven).forEach(System.out::println);

//Printing Even Numbers
System.out.println("------Even Numbers-------");
arrNumbers.stream().filter(no -> no%2==0).forEach(System.out::println);

//Printing Odd Numbers
System.out.println("------Odd Numbers-------");
arrNumbers.stream().filter(no -> no%2==1).forEach(System.out::println);

//Printing Odd Numbers
System.out.println("------Print Spring Skills-------");
arrSkills.stream().filter(skill -> skill.toLowerCase().contains("spring"))
.forEach(System.out::println);

private static boolean isEven(int no){
        return no%2==0;
}       

Output

------Even Numbers-------
10
40
44
48
50
------Odd Numbers-------
27
31
35
------Print Spring  Skills-------
Spring Boot
Spring Security
Spring MVC

Map

  1. Map takes a function as a argument and performs transform action on elements. The Output of Map is a Stream
  2. map() is used to transform one object into another by applying a function.
  3. Stream.map(Function mapper) takes a function as an argument.
  4. mapping function converts one object to the other. Then, the map() function will do the transformation for you. It is also an intermediate Stream operation, which means you can call other Stream methods, like a filter, or collect on this to create a chain of transformations.
List<Integer> arrNumbers = List.of(10,27,31, 35, 40, 44, 48, 50);
List<String> arrSkills = List.of("Spring Boot", "Spring Security", "Java 8", "Microservices", "Spring MVC");

//Printing Square of Numbers
System.out.println("------Square of Numbers-------");
arrNumbers.stream()
		.filter(no -> no%2==0)
		.map(no -> no*no)
		.forEach(System.out::println);

//Print Total Characters in String
System.out.println("------Print Total Characters in String-------");
arrSkills.stream()
		.map(skill -> skill + " contains "+ skill.length()+ " Characters")
		.forEach(System.out::println);

Reduce

  1. Stream.reduce() takes function as Parameter
  2. Reduction stream operations allow us to produce one single result from a sequence of elements, by repeatedly applying a combining operation to the elements in the sequence.
  3. Stream.reduce() operation Contains Identity, Accumulator and Combiner
  4. Identity – an element that is the initial value of the reduction operation and the default result if the stream is empty
  5. Accumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
  6. Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation

ReduceEgs.java

import java.util.Arrays;
import java.util.List;

public class ReduceEgs {
    public static void main(String[] args) {
        List<Integer> arrNumbers =  Arrays.asList(1,2,3,4,5,6,7,8,9);

        System.out.println(arrNumbers.stream().reduce(0, ReduceEgs::sumNos));
    }

    public static Integer sumNos(int x, int y){
        System.out.println("a -"+ x + " b - "+  y);

        return x+y;
    }
}

Output

a -0 b - 1
a -1 b - 2
a -3 b - 3
a -6 b - 4
a -10 b - 5
a -15 b - 6
a -21 b - 7
a -28 b - 8
a -36 b - 9
45

In the above example

  1. the Integer value 0 is the identity. It stores the initial value of the reduction operation and also the default result when the stream of Integer values is empty.
  2. the lambda expression x+y represented by function sumNos is the accumulator since it takes the partial sum of Integer values and the next element in the stream.
  3. When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner

Role of combiner would be visibile only in parallelStream with output as below. It would be hard to interpret the output response in console.

ReduceEgs.java

.
.
 System.out.println(arrNumbers.parallelStream().reduce(0, ReduceEgs::sumNos));
.
.

Output

a -0 b - 6
a -0 b - 5
a -5 b - 6
a -0 b - 1
a -0 b - 7
a -0 b - 9
a -0 b - 2
a -1 b - 2
a -0 b - 3
a -0 b - 8
a -8 b - 9
a -0 b - 4
a -3 b - 4
a -3 b - 7
a -7 b - 17
a -11 b - 24
a -10 b - 35
45

Alternate ways to Sum Nos

public static void main(String[] args) {
 List<Integer> arrNumbers =  Arrays.asList(1,2,3,4,5,6,7,8,9);

 Integer sum = arrNumbers.stream().reduce(0, Integer::sum);
 Integer sum2 = arrNumbers.stream().reduce(0, (x,y)->x+y);

 System.out.println(sum);
 System.out.println(sum2);
}

Comments are closed.