Transcript
Page 1: Java 8: more readable and flexible code

Wri$ng  more  concise  and  flexible  code  with  Java  8  

Raoul-­‐Gabriel  Urma  @raoulUK  

1  

Page 2: Java 8: more readable and flexible code

uname  -­‐a  •  PhD  at  University  of  Cambridge  (2011  -­‐  current)  –  Source  code  analysis,    automated  refactoring,  type  systems,  programming  languages  

•  MEng  Imperial  College  London  (2007  -­‐  2011)    •  Google  (Python  team),  Oracle  (Java  team),  Goldman  Sachs,  

eBay  •  Regular  author  for  Oracle  Java  Magazine  •  Conference  speaker:  Fosdem,  Devoxx…  

2  

Page 3: Java 8: more readable and flexible code

What  I’m  going  to  cover  

•  Why  Java  8?  (5min)  •  Behaviour  parameterisa$on  (10min)  •  Lambda  expressions  (20min)  •  Streams  (15min)  •  Op$onal  (5min)  •  Default  methods  (10min)  

3  

Page 4: Java 8: more readable and flexible code

Java  8  in  Ac$on:  Lambdas,  Streams  and  func$onal-­‐style  programming  

4  

•  Co-­‐authored  with  Mario  Fusco  &  Alan  Mycro`  •  Most  complete  book  on  Java  8  

h"p://manning.com/urma  

Page 5: Java 8: more readable and flexible code

Why  Java  8  

Before:  Collec$ons.sort(inventory,  new  Comparator<Apple>()  {            public  int  compare(Apple  a1,  Apple  a2){                  return  a1.getWeight().compareTo(a2.getWeight());            }  });    

A5er:  inventory.sort(comparing(Apple::getWeight));  

5  

Page 6: Java 8: more readable and flexible code

Why  Java  8?  

6  

List<Dish>  lowCaloricDishes  =  new  ArrayList<>();  for(Dish  d:  dishes){          if(d.getCalories()  <  400){                  lowCaloricDishes.add(d);          }  }    List<String>  lowCaloricDishesName  =  new  ArrayList<>();  Collec$ons.sort(lowCaloricDishes  ,  new  Comparator<Dish>()  {          public  int  compare(Dish  d1,  Dish  d2){                  return  Integer.compare(d1.getCalories(),  d2.getCalories());          }  });    for(Dish  d:  lowCaloricDishes){          lowCaloricDishesName.add(d.getName());  }     6  

sor$ng  by  calories  

filtering  low  calories  

Extract  names  

Page 7: Java 8: more readable and flexible code

Why  Java  8?  

7  7  

List<String>  lowCaloricDishesName  =                                  dishes.stream()                                            .filter(d  -­‐>  d.getCalories()  <  400)                                            .sorted(comparing(Dish::getCalories))                                            .map(Dish::getName)                                            .collect(toList());  

Page 8: Java 8: more readable and flexible code

Why  Java  8?    (  as  seen  by  language  designers)  

•  Commodity  CPUs  are  mul$core  (e.g.  4  cores)  •  Analogy:  you  have  4  assistants,  in  theory  you  could  get  the  work  done  4  $mes  faster!  

•  In  prac$ce:    –  it’s  hard  because  you  now  have  to  figure  out  how  to  distribute  a  piece  of  work  amongst  4  people.    

–  It’s  easier  to  just  pass  the  whole  piece  of  work  to  one  person.  

8  

Page 9: Java 8: more readable and flexible code

Why  Java  8?    (  as  seen  by  language  designers)  

•  Vast  majority  of  Java  programs  use  only  one  of  these  cores  and  leave  the  others  idle  

•  Why?  wri$ng  efficient  parallel  code  is  hard  – summing  an  array  with  a  for  loop  is  easy  – how  to  sum  an  array  on  4  cores?  

9  

Page 10: Java 8: more readable and flexible code

Why  Java  8?    (  as  seen  by  language  designers)  

•  Java  8  introduces  features  that  make  parallel  data  processing  easier  

•  Driven  from  three  concepts:  – stream  processing  – behaviour  parameterisa$on  ("passing  code")  – no  shared  mutable  data  

10  

Page 11: Java 8: more readable and flexible code

Stream  processing  

 cat  file1  file2  |  tr  "[A-­‐Z]"  "[a-­‐z]"  |  sort  |  tail  -­‐3      

11  

!

Page 12: Java 8: more readable and flexible code

Stream  processing  List<String>  lowCaloricDishesName  =          dishes.parallelStream()                                .filter(d  -­‐>  d.getCalories()  <  400)                                .sorted(comparing(Dish::getCalories))                                .map(Dish::getName)                                .collect(toList());  

12  

stream  processing  

Page 13: Java 8: more readable and flexible code

Behaviour  parameterisa$on  

13  

Page 14: Java 8: more readable and flexible code

Behaviour  parameterisa$on    

List<String>  lowCaloricDishesName  =          dishes.parallel()                                .filter(d  -­‐>  d.getCalories()  <  400)                                .sorted(comparing(Dish::getCalories))                                .map(Dish::getName)                                .collect(toList());  

14  

lambda  expression  

method  reference  

Page 15: Java 8: more readable and flexible code

No  shared  mutable  data  List<String>  lowCaloricDishesName  =          dishes.parallelStream()                                .filter(d  -­‐>  d.getCalories()  <  400)                                .sorted(comparing(Dish::getCalories))                                .map(Dish::getName)                                .collect(toList());  

15  

Can  be  duplicated  and  ran  on  disjoint  part  of  input  

Page 16: Java 8: more readable and flexible code

Java  8  

•  Introduces  a  concise  way  to  pass  behaviour  –  lambda  expressions,  method  references  

•  Introduces  an  API  to  process  data  in  parallel  – Streams  API  – several  opera$ons  such  as  filter,  map,  reduce  can  be  parameterised  with  lambdas  

•  Also:  default  methods  (more  later)  – more  flexible  inheritance  

16  

Page 17: Java 8: more readable and flexible code

Behaviour  parameterisa$on  

•  Goal:  abstract  over  behaviour  – Do  <something>  for  every  element  in  a  list  – Do  <something>  else  when  the  list  is  finished  –   Do  <yet  something  else>  if  an  error  occurs  

•  Why  should  you  care?  – Adapt  to  changing  requirements  –  Java  8  Streams  API  heavily  relies  on  it  

17  

Page 18: Java 8: more readable and flexible code

1st  awempt:  fitering  green  apples  public  sta$c  List<Apple>  filterGreenApples(List<Apple>  inventory)  {            List<Apple>  result  =  new  ArrayList<>();            for(Apple  apple:  inventory){                  if("green".equals(apple.getColor()  )  {                          result.add(apple);                  }          }          return  result;  }  

18  

Page 19: Java 8: more readable and flexible code

2nd  awempt:  abstrac$ng  color  public  sta$c  List<Apple>    filterApplesByColour(List<Apple>  inventory,  String  color)  {          List<Apple>  result  =  new  ArrayList<>();            for  (Apple  apple:  inventory){                  if  (apple.getColor().equals(color)))  {                          result.add(apple);  }                  }                return  result;  }  

19  

List<Apple>  greenApples  =  filterApplesByColor(inventory,  "green");    List<Apple>  redApples  =  filterApplesByColor(inventory,  "red");  

Page 20: Java 8: more readable and flexible code

2nd  awempt:  abstrac$ng  weight  public  sta$c  List<Apple>    filterApplesByWeight(List<Apple>  inventory,  int  weight)  {          List<Apple>  result  =  new  ArrayList<>();            for  (Apple  apple:  inventory){                  if  (apple.getWeight()  >  weight)  {                          result.add(apple);  }                  }                return  result;  }  

20  

List<Apple>  heavyApples  =  filterApplesByWeight(inventory,    150);    List<Apple>  megaHeavyApples  =  filterApplesByWeight(inventory,    250);  

Page 21: Java 8: more readable and flexible code

3rd  awempt:  filtering  with  everything  

public  sta$c  List<Apple>    filter  (List<Apple>  inventory,  String  color,  int  weight,  boolean  flag)  {          List<Apple>  result  =  new  ArrayList<>();          for  (Apple  apple:  inventory){                  if  (  (flag  &&  apple.getColor().equals(color))                              ||  (!flag  &&  apple.getWeight()  >  weight)  ){                          result.add(apple);  }          }          return  result;  }  

21  

List<Apple>  greenApples  =  filter(inventory,  "green",  0,  true);  List<Apple>  heavyApples  =  filter(inventory,  "",  150,  false);  

Page 22: Java 8: more readable and flexible code

4th  (a)  awempt:  modeling  selec$on  criteria  

public  interface  ApplePredicate{            public  boolean  test  (Apple  apple);  }    public  class  AppleWeightPredicate  implements  ApplePredicate{            public  boolean  test(Apple  apple){                  return  apple.getWeight()  >  150;            }  }  public  class  AppleColorPredicate  implements  ApplePredicate{          public  boolean  test(Apple  apple){                  return  "green".equals(apple.getColor());            }  }  

22  

Page 23: Java 8: more readable and flexible code

4th  (a)  awempt:  modeling  selec$on  criteria  

23  

Page 24: Java 8: more readable and flexible code

4th  (b)  awempt:  filtering  by  an  abstract  criteria  

public  sta$c  List<Apple>    filter(List<Apple>  inventory,  ApplePredicate  p){          List<Apple>  result  =  new  ArrayList<>();          for(Apple  apple:  inventory){                  if(p.test(apple)){                          result.add(apple);  �                }          }          return  result;  }  

24  

Page 25: Java 8: more readable and flexible code

Let’s  pause  for  a  liwle  bit  

•  Our  code  is  much  more  flexible!  –  can  create  any  kinds  of  selec$on  criteria  on  an  Apple  –  re-­‐use  of  code  for  filter  

•  However,  declaring  many  selec$on  criterias  using  classes  is  verbose…  L  – we  have  the  right  abstrac$on  but  not  good  concision  – we  need  a  bewer  way  to  create  and  pass  behaviours  

25  

Page 26: Java 8: more readable and flexible code

5th  awempt:  anonymous  classes  List<Apple>  result  =  filter(inventory,  new  ApplePredicate()  {          public  boolean  test(Apple  apple){                  return  "red".equals.(apple.getColor());          }  });    List<Apple>  result  =  filter(inventory,  new  ApplePredicate()  {          public  boolean  test(Apple  apple){                  return  apple.getWeight()  >  150;          }  });     26  

Page 27: Java 8: more readable and flexible code

6th  awempt:  Java  8  lambdas  List<Apple>  result  =            filter(inventory,  (Apple  apple)  -­‐>  "red".equals.(apple.getColor()));    List<Apple>  result  =            filter(inventory,  (Apple  apple)  -­‐>  apple.getWeight()  >  150);    

27  

Great  because  closer  to  problem  statement!  

Page 28: Java 8: more readable and flexible code

7th  awempt:  abstrac$ng  over  the    list  type    

public  sta$c  <T>  List<T>  filter  (List<T>  list,  Predicate<T>  p)  {            List<T>  result  =  new  ArrayList<>();            for(T  e:  list){                  if(p.test(e))  {                          result.add(e);                  }          }          return  result;  }  

28  

Page 29: Java 8: more readable and flexible code

8th  awempt:  Java  8  lambdas  again  List<String>  result  =            filter(strings,  (String  s)  -­‐>    s.endsWith("JDK"));    List<Integer>  result  =            filter(numbers,  (Integer  i)  -­‐>  i  %  2  ==  0);    List<Apple>  result  =            filter(inventory,  (Apple  a)  -­‐>  apple.getWeight()  >  150);    

29  

Page 30: Java 8: more readable and flexible code

Moral  of  the  story  

•  Behaviour  parameterisa$on  lets  you  write  more  flexible  code  – Adapt  for  changes  – Avoids  code  duplica$on  

•  To  encourage  this  style  of  programming  we  need  a  concise  way  to  create  and  pass  behaviours  –  Java  8  brings  lambda  expressions  to  help!  

30  

Page 31: Java 8: more readable and flexible code

Flexible  

Concise  

Anonymous  classes  

Verbose  

Rigid  

Lambdas  Class  +  Instance  

Value  parameterisa$on  

Behaviour  parameterisa$on  

Value  vs  Behaviour  parameterisa$on  

Page 32: Java 8: more readable and flexible code

Lambda  expressions:  what  is  it?  

•  A  lambda  expression  is:    – a  kind  of  anonymous  func$on    –  that  can  be  passed  around:    –  It  doesn’t  have  a  name,  but  it  has  a  list  of  parameters,  a  body,  a  return  type,  and  also  possibly  a  list  of  excep$ons  that  can  be  thrown.    

32  

Page 33: Java 8: more readable and flexible code

In  a  nutshell  

33  

Page 34: Java 8: more readable and flexible code

Lambda  expressions:  what  is  it?  

•  A  lambda  expression  is:    – a  kind  of  anonymous  func$on      

•  Anonymous:  doesn’t  have  an  explicit  name  like  a  method:  less  to  write  and  think  about!  

•  Func$on:  not  associated  to  a  class  like  a  method  is  

34  

Page 35: Java 8: more readable and flexible code

Lambda  expressions:  what  is  it?  

•  A  lambda  expression  is:    – a  kind  of  anonymous  func$on    –  that  can  be  passed  around:    

•  Passed  around:  A  lambda  expression  can  be  passed  as  argument  to  a  method  or  stored  in  a  variable  

35  

Page 36: Java 8: more readable and flexible code

Lambda  expressions:  what  is  it?  

•  A  lambda  expression  is:    – a  kind  of  anonymous  func$on    –  that  can  be  passed  around:    –  it  doesn’t  have  a  name,  but  it  has  a  list  of  parameters,  a  body,  a  return  type,  and  also  possibly  a  list  of  excep$ons  that  can  be  thrown.  

•   Concise:  you  don’t  need  to  write  a  lot  of  boilerplate  like  you  do  for  anonymous  classes.  

36  

Page 37: Java 8: more readable and flexible code

Goal  

•  Goal:  let  you  pass  a  piece  of  behaviour/code  in  a  concise  way  

•  You  can  cope  with  changing  requirements  by  using  a  behaviour,  represented  by  a  lambda,  as  a  parameter  to  a  method  

•  You  no  longer  need  to  choose  between  abstracaon  and  concision!    

37  

Page 38: Java 8: more readable and flexible code

Before/A`er  

Before:  inventory.sort(new  Comparator<Apple>()  {            public  int  compare(Apple  a1,  Apple  a2){                  return  a1.getWeight().compareTo(a2.getWeight());            }  });  

 

A5er:  inventory.sort((Apple  a1,  Apple  a2)  -­‐>  a1.getWeight().compareTo(a2.getWeight()));  

38  

Page 39: Java 8: more readable and flexible code

Examples  

39  

Use  case   Example  of  lambda  A  boolean  expression   (List<String>  list)  -­‐>  list.isEmpty()  Crea$ng  objects   ()  -­‐>  new  Apple(10)  Consuming  from  an  object   (Apple  a)  -­‐>  System.out.println(a.getWeight())  Select/extract  from  an  object   (String  s)  -­‐>  s.length()  Combine  two  values   (int  a,  int  b)  -­‐>  a  *  b  Compare  two  objects   (Apple  a1,  Apple  a2)  -­‐>  

a1.getWeight().compareTo(a2.getWeight())  

Page 40: Java 8: more readable and flexible code

Where  and  how  to  use  lambdas?  

40  

•  Java  lets  you  pass  expressions  only  where  a  type  is  expected  

•  So  what’s  the  type  of  a  lambda  expression?  

Page 41: Java 8: more readable and flexible code

Func$onal  interface  (1)  

41  

•  The  type  of  a  lambda  expression  is  essen$ally  a  funcaonal  interface  

•  A  func$onal  interface  is  an  interface  that  declares  exactly  one  (abstract)  method.    

Page 42: Java 8: more readable and flexible code

Func$onal  interface  (2)  

42  

//  java.u$l.Comparator  public  interface  Comparator<T>  {          public  int  compare(T  o1,  T  o2);    }    public  interface  Runnable  {          public  void  run();    }    public  interface  ApplePredicate  {            public  boolean  test  (Apple  a);  }  

Page 43: Java 8: more readable and flexible code

Func$onal  interface  &  Lambdas  

43  

•  The  signature  of  the  abstract  method  of  the  func$onal  interface  essen$ally  describes  the  signature  of  the  lambda  expression.  

•  Lambda  expressions  let  you  provide  the  implementa$on  of  the  abstract  method  of  a  func$onal  interface  directly  inline  and  treat  the  whole  expression  as  an  instance  of  a  func$onal  interface.  

Page 44: Java 8: more readable and flexible code

Func$onal  interface  &  Lambdas  

44  

Runnable  r1  =  ()  -­‐>  System.out.println("Hello  World  1");  Runnable  r2  =  new  Runnable(){            public  void  run(){                  System.out.println("Hello  World  2");            }  }  public  void  process(Runnable  r){            r.run();  }  process(r1);    process(r2);    process(()  -­‐>  System.out.println("Hello  World  3"));  

Page 45: Java 8: more readable and flexible code

Execute  Around  Pawern  

45  

Open    ressource  

Do  some  processing  

Close  ressource  

Page 46: Java 8: more readable and flexible code

Execute  Around  Pawern  

46  

public  sta$c  String  processFile()  throws  IOExcep$on  {          try  (BufferedReader  br  =                                                      new  BufferedReader(new  FileReader("data.txt")))  {                  return  br.readLine();            }  }    

•  This  current  code  is  limited.  You  can  read  only  the  first  line  of  the  file.    

 

Page 47: Java 8: more readable and flexible code

What  we  want  

47  

String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine());      String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine()  +  br.readLine());      

Page 48: Java 8: more readable and flexible code

Step  1:  Introducing  func$onal  interface  

48  

public  interface  BufferedReaderProcessor  {          public  String  process(BufferedReader  b)  throws  IOExcep$on;    }    public  sta$c  String  processFile(BufferedReaderProcessor  p)  throws  IOExcep$on  {  ...    }      

Page 49: Java 8: more readable and flexible code

Step  2:  Execu$ng  a  behaviour  

49  

public  sta$c  String    processFile(BufferedReaderProcessor  p)  throws  IOExcep$on  {          try  (BufferedReader  br  =                                                new  BufferedReader(new  FileReader("data.txt")))  {                  return  p.process(br);            }  }    String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine());      String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine()  +  br.readLine());        

Page 50: Java 8: more readable and flexible code

Lots  of  func$onal  interfaces  

50  

Funcaonal  interface   Lambda  signature  Predicate<T>   T  -­‐>  boolean  Consumer<T>   T  -­‐>  void  Func$on<T,  R>   T  -­‐>  R  Supplier<T>   ()  -­‐>  T  UnaryOperator<T>   T  -­‐>  T  Binaryoperator<T>   (T,  T)  -­‐>  T  BiFunc$on<T,  U,  R>     (T,  U)  -­‐>  R  

•  Have  a  look  in  java.u$l.func$on.*  

Page 51: Java 8: more readable and flexible code

Method  references  

51  

•  Method  references  let  you  reuse  exis$ng  method  defini$ons  and  pass  them  just  like  lambdas.  «  First-­‐class  »  func$ons  

•  Just  a  syntac'c  suggar  to  lambdas  

Before:  (Apple  a)  -­‐>  a.getWeight()  A5er:  Apple::getWeight    Before:  (str,  i)  -­‐>  str.substring(i)  A5er:  String::substring  

 

Page 52: Java 8: more readable and flexible code

Recipes  

52  

Page 53: Java 8: more readable and flexible code

Bewer  code  with  Java  8:    a  prac$cal  example  

53  

 public  class  AppleComparator  implements  Comparator<Apple>  {            public  int  compare(Apple  a1,  Apple  a2){                  return  a1.getWeight().compareTo(a2.getWeight());          }  }    inventory.sort(new  AppleComparator());  

Page 54: Java 8: more readable and flexible code

Anonymous  class  

54  

inventory.sort(new  Comparator<Apple>()  {            public  int  compare(Apple  a1,  Apple  a2){                  return  a1.getWeight().compareTo(a2.getWeight());            }  });  

Page 55: Java 8: more readable and flexible code

Lambdas  

55  

inventory.sort(      (Apple  a1,  Apple  a2)  -­‐>  a1.getWeight().compareTo(a2.getWeight())  );      

Page 56: Java 8: more readable and flexible code

Lambdas  

56  

inventory.sort(      (Apple  a1,  Apple  a2)  -­‐>  a1.getWeight().compareTo(a2.getWeight())  );      With  type  inference:  inventory.sort(      (a1,  a2)  -­‐>  a1.getWeight().compareTo(a2.getWeight())  );    

Page 57: Java 8: more readable and flexible code

A  bit  of  help  from  library  

57  

Comparator<Apple>  byWeight  =            Comparator.comparing((Apple  a)  -­‐>  a.getWeight());    inventory.sort(byWeight);      

Page 58: Java 8: more readable and flexible code

Method  references  

58  

Comparator<Apple>  byWeight  =            Comparator.comparing(Apple::getWeight);    inventory.sort(byWeight);      

Page 59: Java 8: more readable and flexible code

Tidy  up  

59  

import  sta$c  java.u$l.Comparator.comparing;  inventory.sort(comparing(Apple::getWeight));      Reads  like  probable  statement!  

Page 60: Java 8: more readable and flexible code

Streams  

60  

•  Nearly  every  Java  applica$ons  makes  and  processes  collec$ons  

•  However  processing  collec$ons  is  far  from  perfect:  – SQL  like  opera$ons?  – How  to  efficiently  process  large  collec$ons?  

Page 61: Java 8: more readable and flexible code

SQL-­‐like  opera$ons  

61  

•  Many  processing  pawerns  are  SQL-­‐like  – finding  a  transac$on  with  highest  value  – grouping  transac$ons  related  to  grocery  shopping  

•  Re-­‐implemented  every  $me  •  SQL  is  declaraave  – express  what  you  expect  not  how  to  implement  a  query  

– SELECT  id,  MAX(value)  from  transac$ons  

Page 62: Java 8: more readable and flexible code

Example:  Java  7  

62  

List<Transac$on>  groceryTransac$ons  =  new  Arraylist<>();  for(Transac$on  t:  transac$ons){      if(t.getType()  ==  Transac$on.GROCERY){          groceryTransac$ons.add(t);      }  }  Collec$ons.sort(groceryTransac$ons,  new  Comparator(){      public  int  compare(Transac$on  t1,  Transac$on  t2){          return  t2.getValue().compareTo(t1.getValue());      }  });  List<Integer>  transac$onIds  =  new  ArrayList<>();  for(Transac$on  t:  groceryTransac$ons){      transac$onsIds.add(t.getId());  }        

sor$ng  by  decreasing  value  

filtering  grocery  transac$ons  

extract  Ids  

Page 63: Java 8: more readable and flexible code

Example:  Java  8  

63  

List<Integer>  transac$onsIds  =            transacaons.stream()                                  .filter(t  -­‐>  t.getType()  ==  Transac$on.GROCERY)                                  .sorted(comparing(Transac$on::getValue).reversed())                                  .map(Transac$on::getId)                                  .collect(toList());  

Page 64: Java 8: more readable and flexible code

Example:  Java  8  -­‐  parallel  

64  

List<Integer>  transac$onsIds  =            transacaons.parallelStream()                                  .filter(t  -­‐>  t.getType()  ==  Transac$on.GROCERY)                                  .sorted(comparing(Transac$on::getValue).reversed())                                  .map(Transac$on::getId)                                  .collect(toList());  

Page 65: Java 8: more readable and flexible code

Ok  cool  –  so  what’s  a  Stream?  

65  

•  Informal:  a  fancy  iterator  with  database-­‐like  opera$ons  

•  Formal:  A  sequence  of  elements  from  a  source  that  supports  aggregate  opera$ons.  

Page 66: Java 8: more readable and flexible code

Ok  cool  –  so  what’s  a  Stream?  

66  

•  Sequence  of  elements:  a  stream  provides  an  interface  to  a  sequenced  set  of  values  of  a  specific  element  type.  However,  streams  don’t  actually  store  elements,  they  are  computed  on  demand.  

Page 67: Java 8: more readable and flexible code

Ok  cool  –  so  what’s  a  Stream?  

67  

•  Source:  Streams  consume  from  a  data-­‐providing  source  such  as  Collec$ons,  Arrays,  or  IO  resources.  

Page 68: Java 8: more readable and flexible code

Ok  cool  –  so  what’s  a  Stream?  

68  

•  Aggregate  operaaons:  Streams  support  SQL-­‐like  opera$ons  and  common  opera$ons  from  func$onal  programing  languages  such  as  filter,  map,  reduce,  find,  match,  sorted  etc.  

Page 69: Java 8: more readable and flexible code

Two  addi$onal  proper$es  

69  

•  Pipelining:  Many  stream  opera$ons  return  a  stream  themselves.  This  allows  opera$ons  to  be  chained  and  form  a  larger  pipeline  as  well  as  certain  op$misa$ons  (more  later).    

•  Internal  iteraaon:  In  contrast  to  collec$ons,  that  are  iterated  explicitly  (“external  itera$on”),  stream  opera$ons  do  the  itera$on  behind  the  scene  for  you.  

Page 70: Java 8: more readable and flexible code

70  

Pipelining  

•  Intermediate  operaaons:  return  a  Stream  and  can  be  “connected”  

•  Terminal  operaaons:  computes  the  result  of  the  pipeline  

   

Intermediate  opera$ons   Terminal  opera$on  

Page 71: Java 8: more readable and flexible code

71  

Internal  Itera$on  

Page 72: Java 8: more readable and flexible code

72  

Page 73: Java 8: more readable and flexible code

Laziness  &  short-­‐circui$ng  

73  

List<Integer>  numbers  =  Arrays.asList(1,  2,  3,  4,  5,  6,  7,  8);  List<Integer>  twoEvenSquares  =            numbers.stream()                        .filter(n  -­‐>  n  %  2  ==  0)                        .map(n  -­‐>  n  *  n)                        .limit(2)                        .collect(toList());  

Page 74: Java 8: more readable and flexible code

Laziness  &  loop  fusion  &  short-­‐circui$ng  

74  

List<Integer>  numbers  =  Arrays.asList(1,  2,  3,  4,  5,  6,  7,  8);  List<Integer>  twoEvenSquares  =            numbers.stream()                        .filter(n  -­‐>  n  %  2  ==  0)                        .map(n  -­‐>  n  *  n)                        .limit(2)                        .collect(toList());  

 •  filtering  1  •  filtering  2  •  mapping  2  •  filtering  3  •  filtering  4  •  mapping  4    

Page 75: Java 8: more readable and flexible code

Many  opera$ons  

75  

•  Filtering:  filter,  dis$nct,  limit,  skip  •  Finding/Matching:  anyMatch,  allMatch,  noneMatch,  findAny,  findFirst  

•  Mapping:  map,  flatMap  •  Reducing:  reduce  

Page 76: Java 8: more readable and flexible code

Streams:  much  more  (1)  Map<Dish.Type,  List<Dish>>  dishesbyType  =  new  HashMap<>();    for  (Dish  dish:  menu)  {    

 Dish.Type  type=  dish.getType();    List<Dish>  dishesForType  =  dishesbyType  .get(type);    if  (dishesForType  ==  null)  {      dishesForType  =  new  ArrayList<>();      dishesbyType  .put(type,  dishesForType);    }    dishesForType  .add(dish);  

}        

76  

Page 77: Java 8: more readable and flexible code

Streams:  much  more(2)  

77  

Map<Dish.Type,  List<Dish>>  dishesByType  =            menu.stream().collect(groupingBy(Dish::getType));    {FISH=[prawns,  salmon],  OTHER=[french  fries,  rice,  season  fruit,  pizza],  MEAT=[pork,  beef,  chicken]}      

Page 78: Java 8: more readable and flexible code

Streams:  much  more(3)  Map<Boolean,  Map<Dish.Type,  List<Dish>>>  vegetarianDishesByType  =    menu.stream().collect(    

   paraaoningBy(Dish::isVegetarian,  groupingBy(Dish::getType)));        •  Produces  a  two-­‐level  Map:  {false={FISH=[prawns,  salmon],  MEAT=[pork,  beef,  chicken]},  true={OTHER=[french  fries,  rice,  season  fruit,  pizza]}}    

78  

Page 79: Java 8: more readable and flexible code

Step  1:  sequen$al  for  loop  

public  sta$c  long  itera$veSum(long  n)  {                  long  result  =  0;                  for  (long  i  =  0;  i  <  n;  i++)  {                          result  +=  i;                  }                  return  result;          }    

79  

3ms  

Page 80: Java 8: more readable and flexible code

Step  2:  sequen$al  stream    public  sta$c  long  sequen$alSum(long  n)  {                  return  Stream.iterate(1L,  i  -­‐>  i  +  1)                                                                      .limit(n)                                                                      .reduce(Long::sum).get();          }  

80  

98ms  

Page 81: Java 8: more readable and flexible code

Step  3:  parallel  stream    public  sta$c  long  sequen$alSum(long  n)  {                  return  Stream.iterate(1L,  i  -­‐>  i  +  1).parallel()                                                                      .limit(n)                                                                      .reduce(Long::sum).get();          }  

81  

193ms!!  

Page 82: Java 8: more readable and flexible code

Step  4:  improved  sequen$al  stream  

 public  sta$c  long  rangedSum(long  n)  {                  return  LongStream.rangeClosed(1,  n)                                                                                    .reduce(Long::sum).getAsLong();          }  

82  

17ms  

Page 83: Java 8: more readable and flexible code

Step  5:  improved  parallel  stream    public  sta$c  long  rangedSum(long  n)  {                  return  LongStream.rangeClosed(1,  n).parallel()                                                                                    .reduce(Long::sum).getAsLong();          }  

83  

1ms  

Page 84: Java 8: more readable and flexible code

Streams:  much  more  (1)  

84  

•  Infinite  streams  •  Collectors:    – collect  – groupingBy  – par$$onBy  

 

Page 85: Java 8: more readable and flexible code

Op$onal<T>  

85  

•  A  new  class  added  in  Java8:  java.u$l.Op$onal  •  Indicates  the  presence  or  absence  of  a  value  •  has  a  bunch  of  method  to  simplify  and  force  “null”  checking  

 Op$onal<Transac$on>  optTransac$on  =            numbers.stream().findAny(t  -­‐>  t.getValue()  <  200);      

Page 86: Java 8: more readable and flexible code

Create  Op$onal  

86  

opt  =  Op$onal.of(notNull);      opt  =  Op$onal.ofNullable(mayBeNull);      opt  =  Op$onal.empty();  

Page 87: Java 8: more readable and flexible code

Op$onal:  do  something  if  there’s  a  value  

87  

Instead  of:  if(transac$on  !=  null){          System.out.println(t);  }    Write:  optTransac$on.ifPresent(System.out::println);  

Page 88: Java 8: more readable and flexible code

Op$onal:  reject  certain  values  

88  

Instead  of:  if(transac$on  !=  null  &&  transac$on.getId()  >  10){          System.out.println(t);  }    Write:  optTransac$on.filter(t  -­‐>  t.getId()  >  10)                                                        .ifPresent(System.out::println);  

Page 89: Java 8: more readable and flexible code

Op$onal:  transform  value  if  present  

89  

Instead  of:  if(transac$on  !=  null){          String  group  =  transac$on.getGroup();          if(“shopping”.equals(group)){                  System.out.println(t);          }  }  Write:  optTransac$on.map(Transac$on::getGroup)                                                        .filter(g  -­‐>  “shopping”.equals(g))                                                        .ifPresent(System.out::println);  

Page 90: Java 8: more readable and flexible code

Op$onal:  default  value  

90  

Instead  of:  int  len  =  (list  !=  null)?  list.size()  :  -­‐1;    Write:  int  len  =  list.map(List::size).orElse(-­‐1);  

Page 91: Java 8: more readable and flexible code

Op$onal:  nested  checking  

91  

Instead  of:  if(transac$on  ==  null){          return  “Unknown”;  }  Des$nator  des$nator  =  transac$on.getDes$nator();  if(des$nator  ==  null){          return  “Unknown”;  }  country  =  des$nator.getCountry();  if(country  ==  null){          return  “Unknown”;  }  return  country.getName()  !=  null  ?  country.getName()  :  “Unknown”;  

Page 92: Java 8: more readable and flexible code

Op$onal:  nested  checking  

92  

transac$on.flatMap(Transac$on::getDes$nator)                                          .flatMap(Transac$on::getCountry)                                          .map(Country::getName)                                          .orElse(“Unknown”);  

Page 93: Java 8: more readable and flexible code

Default  methods  

93  

•  Interfaces  in  Java  8  can  contain  implementa$on  code  

From  List.java:  default  void  sort(Comparator<?  super  E>  c){          Collec$ons.sort(this,  c);  }    

Page 94: Java 8: more readable and flexible code

Goal  

94  

•  Evolve  libraries  •  Adding  a  method  to  an  interface  is  source  incompa$ble  – all  implementers  need  to  support  the  method  –  recompiling  a  class  implemen$ng  the  interface  will  fail  

•  Providing  a  “default”  implementa$on  solves  the  problem  

Page 95: Java 8: more readable and flexible code

95  

Page 96: Java 8: more readable and flexible code

Applica$ons:  Op$onal  methods  

96  

interface  Iterator<T>  {            boolean  hasNext();            T  next();            default  void  remove()  {                    throw  new  UnsupportedOpera$onExcep$on();            }    }    

Page 97: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

97  

•  A  class  has  been  allowed  to  implement  mul$ple  interfaces  since  day  1  of  Java!  

public  class  ArrayList<E>    extends  AbstractList<E>    implements  List<E>,  RandomAccess,  Cloneable,  java.io.Serializable,  Iterable<E>,  Serializable  {    …  }  

 

Page 98: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

98  

Page 99: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

99  

public  interface  Sized  {          public  int  size();          public  default  boolean  isEmpty(){                  return  size()  ==  0;          }  }    

Page 100: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

100  

public  interface  Foreachable<T>  extends  Iterable<T>  {          public  default  void  forEach(Consumer<?  super  T>  block){                  for(T  e:  this){                          block.accept(e);                  }          }  }    

Page 101: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

101  

public  interface  Removeable<T>  extends  Iterable<T>  {          public  default  boolean  removeIf(Predicate<?  super  T>  filter){                  boolean  removed  =  false;                    Iterator<T>  each  =  iterator();                    while(each.hasNext())  {                            if(filter.test(each.next()))  {                                    each.remove();                                    removed  =  true;                            }                    }                    return  removed;            }  }    

Page 102: Java 8: more readable and flexible code

Applica$ons:  mul$ple  inheritance  

102  

Page 103: Java 8: more readable and flexible code

Resolu$on  rules  

103  

1.  Classes  always  win.  A  method  declara$on  in  the  class  or  a  superclass  takes  priority  over  any  default  method  declara$on.  2.  Otherwise,  the  method  with  the  same  signature  in  the  most  specific  default-­‐providing  interface  is  selected.  (If  B  extends  A,  B  is  more  specific  than  A).    

Page 104: Java 8: more readable and flexible code

Use  case  1  

104  

Page 105: Java 8: more readable and flexible code

Use  case  1  

105  

public  interface  A{          public  default  void  hello()  {                    System.out.println("Hello  from  A");          }  }  public  interface  B  extends  A{          public  default  void  hello()  {                    System.out.println("Hello  from  B");          }  }  public  class  C  implements  B,  A  {          public  sta$c  void  main(String...  args)  {                  new  C().hello();  //  ??          }  }    

Page 106: Java 8: more readable and flexible code

Use  case  2  (a)  

106  

public  class  D  implements  A{  }    public  class  C  extends  D  implements  B,  A  {          public  sta$c  void  main(String...  args)  {                  new  C().hello();  //  ??          }  }  

Page 107: Java 8: more readable and flexible code

Use  case  2  (b)  

107  

public  class  D  implements  A{            public  void  hello(){                  System.out.println(“Hello  from  D”);          }  }    public  class  C  extends  D  implements  B,  A  {          public  sta$c  void  main(String...  args)  {                  new  C().hello();  //  ??          }  }  

Page 108: Java 8: more readable and flexible code

Use  case  3  

108  

Page 109: Java 8: more readable and flexible code

Explicit  disambigua$on  

109  

public  class  C  implements  B,  A  {            public  void  hello(){                  B.super.hello();          }  }  

Page 110: Java 8: more readable and flexible code

Use  case  4  

110  

Page 111: Java 8: more readable and flexible code

More…  

111  

•  Func$onal  asynchronous  programming  with  CompleatableFuture  

•  Performance,  Spliterators  •  Recipes  using  Op$onal  •  Tools,  tes$ng  &  debugging  •  Func$onal  programming  in  Java  •  Good  ideas  from  Scala  •  Date/Time  API,  Java  bytecode  &  lambdas  

•  Get  the  book  Java  8  in  Acaon  to  find  out  more!!!  •  h"p://manning.com/urma/  38%  discount  code:  vturma01  


Top Related