JAVA 8 REVEALED
LAMBDAS, STREAMS.
Who We are
Bazlur Rahman Rokon
Associate Software Engineer, Therap Services, LLC
Sazzadur Rahman
Software Engineer, Kona Software Lab Ltd.
What’s new in Java 8
1. Lambda Expressions
2. Method references
3. Default methods
4. Bulk Data Operation → Stream API
5. Date-Time
6. And a lot more ……
Assumption
1. We really love abstraction
2. We Actually Build cool Stuffs
3. We are programmers and lazy
4. We work only day time and go home early (Well, we have life, right
:/ )
5. Users want too many features
6. As we are lazy, we don’t want to do too much work.
7. So we love “Less code, do more” philosophy
The Best Code is No Code At All
1. Code is bad
2. It rots
3. It requires periodic maintenance
4. But the fact is, we love coding, more specifically less
coding
Lambda in Action
public interface Runnable {
public abstract void run();
}
Lambda in Action cont.
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("JUGBD Meetup 3.0");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("JUGBD Meetup 3.0");
}
}).start();
Code I’m
interested in
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("JUGBD Meetup 3.0");
}
}).start();
Ceremony
Less code ☺
new Thread(() -> System.out.println("JUGBD Meetup 3.0"))
.start();
What is Lambda Expression
() -> { }
What is Lambda Expression
(Thing t ) -> { }
What is Lambda Expression
(Thing t ) -> { }
(Thing t , More m) -> { }
Let’s have a situation
public class Person {
private String name;
private LocalDate birthday;
private Sex gender;
private String emailAddress;
private String cellNo;
// getters and setters//
What we want to do
1. Search based on characteristics and send
email/call
1. find older than 60 -> then need Elderly allowance
2. find voters
1. kids -> less than 18 -> they are not allowed to
vote, so ignore them
2. sort by name, by age
Take # 1
public void findPersonOlder(List<Person> persons) {
for (Person p : persons) {
if (p.getAge() > 60) {
sendEmail(p.getEmailAddress());
}
}
}
Take #2
public void findEligibleVoters(List<Person> persons) {
for (Person p : persons) {
if (p.getAge() > 18) {
sendEmail(p.getEmailAddress());
}
}
}
Take # 3
public void findTargetAudienceForAd(List<Person> persons) {
for (Person p : persons) {
if (p.getAge() > 25 &&
p.getGender() == Sex.MALE) {
sendEmail(p.getEmailAddress());
}
}
}
A lots of combinations
We can keep going on and on and
on….
Lets parameterize the behavior
public interface PersonPredicate {
public boolean testPerson(Person p);
}
public void processPerson(List<Person> persons,
PersonPredicate predicate) {
for (Person p : persons) {
if (predicate.testPerson(p)) {
sendEmail(p.getEmailAddress());
}
}
}
Revisit Take #2
processPerson(persons, new PersonPredicate() {
@Override
public boolean testPerson(Person p) {
return p.getAge() > 18;
}
});
Revisit Take #3
processPerson(persons, new PersonPredicate() {
@Override
public boolean testPerson(Person p) {
return p.getAge() > 25 &&
p.getGender() == Sex.MALE;
}
});
We want to call as well
public interface PersonConsumer {
public void accept (String phoneNumber);
}
public void processPerson(List<Person> persons,
PersonPredicate predicate,
PersonConsumer consumer) {
for (Person p : persons) {
if (predicate.testPerson(p)) {
String cellNo = p.getCellNo();
consumer.accept(cellNo);
}
}
}
Lets put it a bit harder
public void processPerson(List<Person> persons,
PersonPredicate predicate,
PersonConsumer consumer) {
for (Person p : persons) {
if (predicate.testPerson(p)) {
String cellNo = p.getCellNo();
consumer.accept(cellNo);
}
}
}
public interface PersonMapper {
public String map(Person p);
}
public void processPerson(List<Person> persons,
PersonPredicate predicate,
PersonMapper mapper,
PersonConsumer consumer) {
for (Person p : persons) {
if (predicate.testPerson(p)) {
String value = mapper.map(p);
consumer.accept(value);
}
Good going ..
processPerson(persons,new PersonPredicate() {
@Override
public boolean testPerson(Person p) {
return p.getAge() > 18;
}
}, new PersonMapper() {
@Override
public String map(Person p) {
return p.getCellNo();
}
}, new PersonConsumer() {
@Override
public void accept(String value) {
call(value);
}
});
Achieved behavior parameterization
Powerfull, but verbose and clunky
Revisit the Again
processPerson(persons, new PersonPredicate() {
@Override
public boolean testPerson(Person p) {
return p.getAge() > 18;
}
});
Boilerplate code
processPerson(persons, new PersonPredicate() {
@Override
public boolean testPerson(Person p) {
return p.getAge() > 18;
}
});
We are in the age of Java 8 , lets throw
away boilerplate code
processPerson(persons,
p
return p.getAge() > 18;
);
Our first lambda
processPerson(persons, p -> p.getAge() > 18);
Lets call voters
processPerson(persons,
p -> p.getAge() > 18,
p1 -> p1.getCellNo(),
c -> call(c)
);
Functional Interface
@FunctionalInterface
public interface PersonMapper {
public String map(Person p);
}
public interface PersonPredicate {
public boolean testPerson(Person p);
}
@FunctionalInterface
public interface PersonMapper {
public String map(Person p);
}
Stream API
So we were basically doing
Source -> filter -> map -> apply
Lambda Lambda Lambda
Stream API
persons
.stream()
.filter(p-> p.getAge()>19)
.map(p-> p.getCellNo())
.forEach( c-> call(c));
What is Stream?
•A sequence of elements from a source supporting sequential and parallel
aggregate operations, While completely abstracting the details of low level
multi threading logic.
•Sources can be Any type of Collection, Array, or any I/O operation who
provides data to the Stream.
•Aggregate operations are operations to collect or extract necessary
information from a stream or collection.
What is Stream?
persons
.stream()
.filter(p-> p.getAge()>19)
.map(p-> p.getCellNo())
.forEach( c-> call(c));
Intermdediate Operation
Terminal Operation
Get Stream
Source
Pipelining
Intermdediate Operation
Intermediate Operations
map
flatMap
filter
sorted
distinct
skip
limit
Map and flatMap
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
List<List<Integer>> mapped =
numbers.stream()
.map(number -> Arrays.asList(number -1, number, number +1))
.collect(Collectors.toList());
System.out.println(mapped); //:> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
List<Integer> flattened =
numbers.stream()
.flatMap(number -> Arrays.asList(number -1, number, number +1).stream())
.collect(Collectors.toList());
System.out.println(flattened); //:> [0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5]
Terminal Operation
collect
allMatch
noneMatch
findFirst
findAny
reduce
forEach
allMatch and noneMatch
//Check if All of the students have distinction
Boolean hasAllStudentsWithDistinction = students.stream()
.allMatch(student -> student.getScore() > 80);
//Return true if None of the students are over distinction
Boolean hasAllStudentsBelowDistinction = students.stream()
.noneMatch(student -> student.getScore() > 80);
Reduce
Reduces the whole stream into a single value
//Summing all elements of a stream
Integer sum = numbers.stream()
.reduce(0, (x, y) -> x + y); //reduce(identity, accumulator)
Integer min = numbers.stream()
.reduce(0, Integer::min);
What about having no terminal
Operation?
persons
.stream()
.filter(p-> p.getAge()>19)
.map(p-> p.getCellNo())
Intermdediate Operation
Get Stream
Source
Pipelining Intermdediate Operation
Lazy and Eager
Did you scrolled your facebook timeline, down to the beginning?
Laziness of Stream operations
• Current era is of Big Data, Parallel Processing and being real time.
• When dealing with Big Data Laziness is a big deal.
• Stream API is inherently Lazy and based on “Process on Demand”
behavior.
Laziness of Stream operations
Stream<String> streamOfNames = students.stream()
.map(student -> {
System.out.println("In Map - " +
student.getName());
return student.getName();
});
//Just to add some delay
for (int i = 1; i <= 5; i++) {
Thread.sleep(1000);
System.out.println(i + " sec");
}
//Called a terminal operation on the stream
streamOfNames.collect(Collectors.toList());
Output:
1 sec
2 sec
3 sec
4 sec
5 sec
In Map - Tom
In Map - Chris
In Map - Dave
Short Circuit
//List of first 3 students who have age > 20
students.stream()
.filter(s -> s.getAge() > 20)
.map(Student::getName)
.limit(3)
.collect(Collectors.toList());
Thanks…

Java 8 revealed

  • 1.
  • 2.
    Who We are BazlurRahman Rokon Associate Software Engineer, Therap Services, LLC Sazzadur Rahman Software Engineer, Kona Software Lab Ltd.
  • 3.
    What’s new inJava 8 1. Lambda Expressions 2. Method references 3. Default methods 4. Bulk Data Operation → Stream API 5. Date-Time 6. And a lot more ……
  • 4.
    Assumption 1. We reallylove abstraction 2. We Actually Build cool Stuffs 3. We are programmers and lazy 4. We work only day time and go home early (Well, we have life, right :/ ) 5. Users want too many features 6. As we are lazy, we don’t want to do too much work. 7. So we love “Less code, do more” philosophy
  • 5.
    The Best Codeis No Code At All 1. Code is bad 2. It rots 3. It requires periodic maintenance 4. But the fact is, we love coding, more specifically less coding
  • 6.
    Lambda in Action publicinterface Runnable { public abstract void run(); }
  • 7.
    Lambda in Actioncont. new Thread(new Runnable() { @Override public void run() { System.out.println("JUGBD Meetup 3.0"); } }).start();
  • 8.
    new Thread(new Runnable(){ @Override public void run() { System.out.println("JUGBD Meetup 3.0"); } }).start(); Code I’m interested in
  • 9.
    new Thread(new Runnable(){ @Override public void run() { System.out.println("JUGBD Meetup 3.0"); } }).start(); Ceremony
  • 10.
    Less code ☺ newThread(() -> System.out.println("JUGBD Meetup 3.0")) .start();
  • 11.
    What is LambdaExpression () -> { }
  • 12.
    What is LambdaExpression (Thing t ) -> { }
  • 13.
    What is LambdaExpression (Thing t ) -> { } (Thing t , More m) -> { }
  • 14.
    Let’s have asituation public class Person { private String name; private LocalDate birthday; private Sex gender; private String emailAddress; private String cellNo; // getters and setters//
  • 15.
    What we wantto do 1. Search based on characteristics and send email/call 1. find older than 60 -> then need Elderly allowance 2. find voters 1. kids -> less than 18 -> they are not allowed to vote, so ignore them 2. sort by name, by age
  • 16.
    Take # 1 publicvoid findPersonOlder(List<Person> persons) { for (Person p : persons) { if (p.getAge() > 60) { sendEmail(p.getEmailAddress()); } } }
  • 17.
    Take #2 public voidfindEligibleVoters(List<Person> persons) { for (Person p : persons) { if (p.getAge() > 18) { sendEmail(p.getEmailAddress()); } } }
  • 18.
    Take # 3 publicvoid findTargetAudienceForAd(List<Person> persons) { for (Person p : persons) { if (p.getAge() > 25 && p.getGender() == Sex.MALE) { sendEmail(p.getEmailAddress()); } } }
  • 19.
    A lots ofcombinations We can keep going on and on and on….
  • 20.
    Lets parameterize thebehavior public interface PersonPredicate { public boolean testPerson(Person p); }
  • 21.
    public void processPerson(List<Person>persons, PersonPredicate predicate) { for (Person p : persons) { if (predicate.testPerson(p)) { sendEmail(p.getEmailAddress()); } } }
  • 22.
    Revisit Take #2 processPerson(persons,new PersonPredicate() { @Override public boolean testPerson(Person p) { return p.getAge() > 18; } });
  • 23.
    Revisit Take #3 processPerson(persons,new PersonPredicate() { @Override public boolean testPerson(Person p) { return p.getAge() > 25 && p.getGender() == Sex.MALE; } });
  • 24.
    We want tocall as well public interface PersonConsumer { public void accept (String phoneNumber); }
  • 25.
    public void processPerson(List<Person>persons, PersonPredicate predicate, PersonConsumer consumer) { for (Person p : persons) { if (predicate.testPerson(p)) { String cellNo = p.getCellNo(); consumer.accept(cellNo); } } }
  • 26.
    Lets put ita bit harder public void processPerson(List<Person> persons, PersonPredicate predicate, PersonConsumer consumer) { for (Person p : persons) { if (predicate.testPerson(p)) { String cellNo = p.getCellNo(); consumer.accept(cellNo); } } }
  • 27.
    public interface PersonMapper{ public String map(Person p); }
  • 28.
    public void processPerson(List<Person>persons, PersonPredicate predicate, PersonMapper mapper, PersonConsumer consumer) { for (Person p : persons) { if (predicate.testPerson(p)) { String value = mapper.map(p); consumer.accept(value); }
  • 29.
    Good going .. processPerson(persons,newPersonPredicate() { @Override public boolean testPerson(Person p) { return p.getAge() > 18; } }, new PersonMapper() { @Override public String map(Person p) { return p.getCellNo(); } }, new PersonConsumer() { @Override public void accept(String value) { call(value); } });
  • 30.
  • 31.
    Revisit the Again processPerson(persons,new PersonPredicate() { @Override public boolean testPerson(Person p) { return p.getAge() > 18; } });
  • 32.
    Boilerplate code processPerson(persons, newPersonPredicate() { @Override public boolean testPerson(Person p) { return p.getAge() > 18; } });
  • 33.
    We are inthe age of Java 8 , lets throw away boilerplate code processPerson(persons, p return p.getAge() > 18; );
  • 34.
  • 35.
    Lets call voters processPerson(persons, p-> p.getAge() > 18, p1 -> p1.getCellNo(), c -> call(c) );
  • 36.
    Functional Interface @FunctionalInterface public interfacePersonMapper { public String map(Person p); } public interface PersonPredicate { public boolean testPerson(Person p); } @FunctionalInterface public interface PersonMapper { public String map(Person p); }
  • 37.
  • 38.
    So we werebasically doing Source -> filter -> map -> apply Lambda Lambda Lambda
  • 39.
  • 40.
    What is Stream? •Asequence of elements from a source supporting sequential and parallel aggregate operations, While completely abstracting the details of low level multi threading logic. •Sources can be Any type of Collection, Array, or any I/O operation who provides data to the Stream. •Aggregate operations are operations to collect or extract necessary information from a stream or collection.
  • 41.
    What is Stream? persons .stream() .filter(p->p.getAge()>19) .map(p-> p.getCellNo()) .forEach( c-> call(c)); Intermdediate Operation Terminal Operation Get Stream Source Pipelining Intermdediate Operation
  • 42.
  • 43.
    Map and flatMap List<Integer>numbers = Arrays.asList(1, 2, 3, 4); List<List<Integer>> mapped = numbers.stream() .map(number -> Arrays.asList(number -1, number, number +1)) .collect(Collectors.toList()); System.out.println(mapped); //:> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]] List<Integer> flattened = numbers.stream() .flatMap(number -> Arrays.asList(number -1, number, number +1).stream()) .collect(Collectors.toList()); System.out.println(flattened); //:> [0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5]
  • 44.
  • 45.
    allMatch and noneMatch //Checkif All of the students have distinction Boolean hasAllStudentsWithDistinction = students.stream() .allMatch(student -> student.getScore() > 80); //Return true if None of the students are over distinction Boolean hasAllStudentsBelowDistinction = students.stream() .noneMatch(student -> student.getScore() > 80);
  • 46.
    Reduce Reduces the wholestream into a single value //Summing all elements of a stream Integer sum = numbers.stream() .reduce(0, (x, y) -> x + y); //reduce(identity, accumulator) Integer min = numbers.stream() .reduce(0, Integer::min);
  • 47.
    What about havingno terminal Operation? persons .stream() .filter(p-> p.getAge()>19) .map(p-> p.getCellNo()) Intermdediate Operation Get Stream Source Pipelining Intermdediate Operation
  • 48.
    Lazy and Eager Didyou scrolled your facebook timeline, down to the beginning?
  • 49.
    Laziness of Streamoperations • Current era is of Big Data, Parallel Processing and being real time. • When dealing with Big Data Laziness is a big deal. • Stream API is inherently Lazy and based on “Process on Demand” behavior.
  • 50.
    Laziness of Streamoperations Stream<String> streamOfNames = students.stream() .map(student -> { System.out.println("In Map - " + student.getName()); return student.getName(); }); //Just to add some delay for (int i = 1; i <= 5; i++) { Thread.sleep(1000); System.out.println(i + " sec"); } //Called a terminal operation on the stream streamOfNames.collect(Collectors.toList()); Output: 1 sec 2 sec 3 sec 4 sec 5 sec In Map - Tom In Map - Chris In Map - Dave
  • 51.
    Short Circuit //List offirst 3 students who have age > 20 students.stream() .filter(s -> s.getAge() > 20) .map(Student::getName) .limit(3) .collect(Collectors.toList());
  • 52.