Java 8: more readable and flexible code

  • 641 views
Uploaded on

In this presentation we introduce Java 8’s main new features and show how you can benefit from them to write code that is more readable and more flexible to requirement changes. …

In this presentation we introduce Java 8’s main new features and show how you can benefit from them to write code that is more readable and more flexible to requirement changes.

We will show how:

1) Lambda expressions and behaviour parameterisation let you write concise code that can cope for requirement changes


2) The new Streams API lets you express complex data process queries in a succinct way while automatically leveraging your multi-core architecture


3) Using the new Optional class can let you reduce unexpected NullPointer exceptions


4) Default methods bring a form of multi-inheritance to Java

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
641
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
34
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Wri$ng  more  concise  and  flexible   code  with  Java  8   Raoul-­‐Gabriel  Urma   @raoulUK   1  
  • 2. 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  
  • 3. 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  
  • 4. 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  
  • 5. 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  
  • 6. 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  
  • 7. Why  Java  8?   7   7   List<String>  lowCaloricDishesName  =                                  dishes.stream()                                            .filter(d  -­‐>  d.getCalories()  <  400)                                            .sorted(comparing(Dish::getCalories))                                            .map(Dish::getName)                                            .collect(toList());  
  • 8. 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  
  • 9. 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  
  • 10. 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  
  • 11. Stream  processing    cat  file1  file2  |  tr  "[A-­‐Z]"  "[a-­‐z]"  |  sort  |  tail  -­‐3       11  
  • 12. Stream  processing   List<String>  lowCaloricDishesName  =          dishes.parallelStream()                                .filter(d  -­‐>  d.getCalories()  <  400)                                .sorted(comparing(Dish::getCalories))                                .map(Dish::getName)                                .collect(toList());   12   stream   processing  
  • 13. Behaviour  parameterisa$on   13  
  • 14. 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  
  • 15. 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  
  • 16. 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  
  • 17. 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  
  • 18. 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  
  • 19. 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");  
  • 20. 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);  
  • 21. 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);  
  • 22. 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  
  • 23. 4th  (a)  awempt:  modeling  selec$on   criteria   23  
  • 24. 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  
  • 25. 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  
  • 26. 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  
  • 27. 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!  
  • 28. 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  
  • 29. 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  
  • 30. 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  
  • 31. Flexible   Concise   Anonymous   classes   Verbose   Rigid   Lambdas   Class  +   Instance   Value  parameterisa$on   Behaviour  parameterisa$on   Value  vs  Behaviour  parameterisa$on  
  • 32. 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  
  • 33. In  a  nutshell   33  
  • 34. 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  
  • 35. 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  
  • 36. 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  
  • 37. 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  
  • 38. 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  
  • 39. 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())  
  • 40. 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?  
  • 41. 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.    
  • 42. 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);   }  
  • 43. 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.  
  • 44. 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"));  
  • 45. Execute  Around  Pawern   45   Open    ressource   Do  some  processing   Close  ressource  
  • 46. 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.      
  • 47. What  we  want   47   String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine());       String  result  =            processFile((BufferedReader  br)  -­‐>  br.readLine()  +  br.readLine());      
  • 48. 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  {   ...     }      
  • 49. 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());    
  • 50. 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.*  
  • 51. 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    
  • 52. Recipes   52  
  • 53. 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());  
  • 54. Anonymous  class   54   inventory.sort(new  Comparator<Apple>()  {            public  int  compare(Apple  a1,  Apple  a2){                  return  a1.getWeight().compareTo(a2.getWeight());            }   });  
  • 55. Lambdas   55   inventory.sort(      (Apple  a1,  Apple  a2)  -­‐>  a1.getWeight().compareTo(a2.getWeight())   );      
  • 56. 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())   );    
  • 57. A  bit  of  help  from  library   57   Comparator<Apple>  byWeight  =            Comparator.comparing((Apple  a)  -­‐>  a.getWeight());     inventory.sort(byWeight);      
  • 58. Method  references   58   Comparator<Apple>  byWeight  =            Comparator.comparing(Apple::getWeight);     inventory.sort(byWeight);      
  • 59. Tidy  up   59   import  sta$c  java.u$l.Comparator.comparing;   inventory.sort(comparing(Apple::getWeight));       Reads  like  probable  statement!  
  • 60. 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?  
  • 61. 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  
  • 62. 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  
  • 63. 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());  
  • 64. 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());  
  • 65. 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.  
  • 66. 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.  
  • 67. Ok  cool  –  so  what’s  a  Stream?   67   •  Source:  Streams  consume  from  a  data-­‐providing   source  such  as  Collec$ons,  Arrays,  or  IO   resources.  
  • 68. 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.  
  • 69. 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.  
  • 70. 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  
  • 71. 71   Internal  Itera$on  
  • 72. 72  
  • 73. 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());  
  • 74. 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  
  • 75. Many  opera$ons   75   •  Filtering:  filter,  dis$nct,  limit,  skip   •  Finding/Matching:  anyMatch,  allMatch,   noneMatch,  findAny,  findFirst   •  Mapping:  map,  flatMap   •  Reducing:  reduce  
  • 76. 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  
  • 77. 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]}      
  • 78. 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  
  • 79. 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  
  • 80. 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  
  • 81. 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!!  
  • 82. Step  4:  improved  sequen$al  stream    public  sta$c  long  rangedSum(long  n)  {                  return  LongStream.rangeClosed(1,  n)                                                                                    .reduce(Long::sum).getAsLong();          }   82   17ms  
  • 83. Step  5:  improved  parallel  stream    public  sta$c  long  rangedSum(long  n)  {                  return  LongStream.rangeClosed(1,  n).parallel()                                                                                    .reduce(Long::sum).getAsLong();          }   83   1ms  
  • 84. Streams:  much  more  (1)   84   •  Infinite  streams   •  Collectors:     – collect   – groupingBy   – par$$onBy    
  • 85. 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);      
  • 86. Create  Op$onal   86   opt  =  Op$onal.of(notNull);       opt  =  Op$onal.ofNullable(mayBeNull);       opt  =  Op$onal.empty();  
  • 87. 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);  
  • 88. 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);  
  • 89. 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);  
  • 90. Op$onal:  default  value   90   Instead  of:   int  len  =  (list  !=  null)?  list.size()  :  -­‐1;     Write:   int  len  =  list.map(List::size).orElse(-­‐1);  
  • 91. 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”;  
  • 92. Op$onal:  nested  checking   92   transac$on.flatMap(Transac$on::getDes$nator)                                          .flatMap(Transac$on::getCountry)                                          .map(Country::getName)                                          .orElse(“Unknown”);  
  • 93. 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);   }    
  • 94. 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  
  • 95. 95  
  • 96. Applica$ons:  Op$onal  methods   96   interface  Iterator<T>  {            boolean  hasNext();            T  next();            default  void  remove()  {                    throw  new  UnsupportedOpera$onExcep$on();            }     }    
  • 97. 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  {     …   }    
  • 98. Applica$ons:  mul$ple  inheritance   98  
  • 99. Applica$ons:  mul$ple  inheritance   99   public  interface  Sized  {          public  int  size();          public  default  boolean  isEmpty(){                  return  size()  ==  0;          }   }    
  • 100. 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);                  }          }   }    
  • 101. 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;            }   }  
  • 102. Applica$ons:  mul$ple  inheritance   102  
  • 103. 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).    
  • 104. Use  case  1   104  
  • 105. 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();  //  ??          }   }    
  • 106. 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();  //  ??          }   }  
  • 107. 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();  //  ??          }   }  
  • 108. Use  case  3   108  
  • 109. Explicit  disambigua$on   109   public  class  C  implements  B,  A  {            public  void  hello(){                  B.super.hello();          }   }  
  • 110. Use  case  4   110  
  • 111. 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