52
JAVA 8 REVEALED LAMBDAS, STREAMS.

Java 8 revealed

Embed Size (px)

Citation preview

JAVA 8 REVEALEDLAMBDAS, 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 ……

Assumption1. 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 All1. 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 do1. Search based on characteristics and

send email/call 1. find older than 60 -> then need Elderly

allowance2. find voters1. 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 AgainprocessPerson(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

PipeliningIntermdediate Operation

Intermediate Operations map

flatMap

filter

sorted

distinct

skip

limit

Map and flatMapList<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 distinctionBoolean hasAllStudentsWithDistinction = students.stream() .allMatch(student -> student.getScore() > 80);

//Return true if None of the students are over distinctionBoolean 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 operationsStream<String> streamOfNames = students.stream() .map(student -> { System.out.println("In Map - " + student.getName()); return student.getName(); });//Just to add some delayfor (int i = 1; i <= 5; i++) { Thread.sleep(1000); System.out.println(i + " sec");}//Called a terminal operation on the streamstreamOfNames.collect(Collectors.toList());

Output:1 sec2 sec3 sec4 sec5 secIn Map - TomIn Map - ChrisIn Map - Dave

Short Circuit//List of first 3 students who have age > 20students.stream() .filter(s -> s.getAge() > 20) .map(Student::getName) .limit(3) .collect(Collectors.toList());

Thanks…