Lambda, Streams & Stream APIs

Lambda Expressions

Lambda is anonymous function ( function with no name & not being bounded to an identifier).
So what's the big deal?
Everything in Java is around objects so functions cannot exists with objects but with lambda around, you can have functions without any objects and you can pass them as arguments.

Syntax :
(parameters) -> expression

(parameters) -> {statement1; .... ; statementN;}

() -> expression

Functional Interface

It is an interface with exactly one abstract method. You would actually pass in implementation of method as a lambda expression.
For example, java.util.function package provides numerous functional interfaces.

Consumer is a functional interface used for foreach loop.

You can write your own functional interface too.

Lambda Illustrated

For example :

(a,b) -> a + b

integerList.foreach(x -> { if (x > 2) call1(x); else call2(x); });

Static Method Reference
List<String> names = Arrays.asList("name1","name2","name3");


Instance Reference

method can be invoked using instance reference directly as:

Constructor Reference 

Constructor can be invoked as:

Unbound non-static reference(By Return Type)
For example ,
String class method toLowerCase()
Usage  :   ClassName :: methodName

String str ="abc";

Now, toLowerCase can be invoked as 
s-> s.toLowerCase()
s:: toLowerCase
String ::toLowerCase



Process collection of objects . This method can be invoked on any Class that implements Collection Interface. 

Stream has a source, intermediate & Terminal operation. - Returns Sequential Stream

Collection.parallelStream() - Returns Parallel Stream( Can also be used for sequential stream)

Stream can also be created as :
1> Empty Stream 
Stream.empty() - > Empty String

2> Stream.generate(Supplier)
Stream.generate(new Random()::nextInt).limit(15)
15 elements generated

3> Stream.iterate(Seed, UnaryOperator)
Stream.iterate(0, n->n+1).limit(20)

4> Stream.of()
Stream.of(1) or Stream.of("a","b","c")

String[] arr = new String[]{"str1","str2","str3"};

6> Stream.builder()

7> From Primitives 

8> From file 

9> From String 
String str = "some String";
IntStream it = str.chars();

10> Concatenates 2 Streams
Stream.concat(stream1, stream2)

Something Important about Stream

Stream is one time kind of operation so once executed, it cannot be referenced again unless it is re-executed.
For example,

Stream <Integer> integerStream = Stream.of(1, 2,3)
.filter(x -> x > 1);
integerStream.count() ; //executes well
//At this point stream has already reached its final stage or //terminal  hence following statement will throw exception

integerStream.findAny() ;// throws IllegalStateException

WorkAround :
List<Integer> integerList = Stream.of(1, 2,3)
.filter(x -> x > 1).collect(Collectors.toList());; ;// Valid

Stream Operations 

Returning Stream:
Let's look at methods that returns back another stream ( Please also look at Static Methods returning Stream above) :


Examples : -> str.matches("MyName")).collect(Collectors.toList());

Get a Employee if Found :> emp.getName().equals("Milind"))
.findAny()     //Return a Employee Wrapped under Optional
Here Employee must override equals & hashcode otherwise it will return empty as they are from different memory storage
emp-> emp.getName().equals("Milind"))
.findAny() //Returns employee's name under Optional

Basically flats the array/set/list into Stream of that Object
.map(x -> x.getPreviousEmployers()) //Stream<List<Employers>>



.map(Employee:: getName)

.skip(2) getName)

stream.sorted(), stream.sorted(Comparator)

Returning Actual Object or wrapped in Optional:
stream.findAny()  - Optional<T>

stream.findFirst()- Optional<T>

stream.max(Comparator)- Optional<T>
Integer maxEmpId =
.max(Integer :: compare)

stream.min(Comparator)- Optional<T>

Integer minEmpId =
.min(Integer :: compare)

stream.reduce(binaryOperator)     - Optional<T>
.filter(emp -> emp.getDept().equals("IT")
.reduce((x,y)-> x+y).

stream.reduce(identity,binaryOperator) - T

long initialValue= 10000L; //Misc Expenses
long totalExpenses =
.filter(emp -> emp.getDept().equals("IT")
.reduce(initialValue, (x,y)-> x+y).

Returning Other Types :
stream.reduce(identity,bifunction,binaryOperator) - IdentityType

int[] intArray = {4,3,2};
int result =
.reduce(1, (a,b) -> a * b,  (d,e)-> d* e);

System.out.println(result); //prints 24

int result =
.reduce(1, (a,b) -> a * b,  (d,e)-> d* e);

stream.collect (Collector<R>) - R

Map<Employee.Gender, Long> byGenders =
.filter(emp -> emp.getDept().equals("IT")
.collect(Collectors.groupingBy(x-> x.getGender(), Collectors.counting()));

stream.collect(Supplier, accumulator, combiner) - R


List<String> list = Arrays.asList("s1", "s2", "s3","s4","s5","s6");
List<String> list1 =, ArrayList::add, ArrayList::addAll);

String s =,
                (sb, s1) -> sb.append(",").append(s1),
                (sb1, sb2) ->  sb1.append("->").append(sb2.append("]"))).toString();

Output : ,s1,s2,s3,s4,s5,s6

String s = list.parallelStream().collect(StringBuilder::new,
                (sb, s1) -> sb.append(",").append(s1),
                (sb1, sb2) ->  sb1.append("->").append(sb2.append("]"))).toString();

Output : ,s1->,s2->,s3]]->,s4->,s5->,s6]]]

stream.allMatch(Predicate) - boolean

stream.anyMatch(Predicate) - boolean

stream.noneMatch(Predicate) - boolean

Other Operations:
stream.count()    - long 

stream.forEach(Consumer action)  - void
stream.forEachOrdered(Consumer action) - void

stream.ToArray() - Object[]
stream.toArray(IntFunction A[]) - A[]

Additional : 

No comments:

Post a Comment