java 8: more readable and flexible code

Post on 10-May-2015

736 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Wri$ng  more  concise  and  flexible  code  with  Java  8  

Raoul-­‐Gabriel  Urma  @raoulUK  

1  

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  

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  

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  

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  

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  

Why  Java  8?  

7  7  

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

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  

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  

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  

Stream  processing  

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

11  

!

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

12  

stream  processing  

Behaviour  parameterisa$on  

13  

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  

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  

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  

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  

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  

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");  

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);  

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);  

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  

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

23  

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  

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  

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  

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!  

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  

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  

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  

Flexible  

Concise  

Anonymous  classes  

Verbose  

Rigid  

Lambdas  Class  +  Instance  

Value  parameterisa$on  

Behaviour  parameterisa$on  

Value  vs  Behaviour  parameterisa$on  

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  

In  a  nutshell  

33  

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  

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  

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  

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  

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  

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())  

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?  

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.    

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);  }  

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.  

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"));  

Execute  Around  Pawern  

45  

Open    ressource  

Do  some  processing  

Close  ressource  

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.    

 

What  we  want  

47  

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

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  {  ...    }      

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());        

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.*  

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  

 

Recipes  

52  

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());  

Anonymous  class  

54  

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

Lambdas  

55  

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

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())  );    

A  bit  of  help  from  library  

57  

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

Method  references  

58  

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

Tidy  up  

59  

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

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?  

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  

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  

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());  

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());  

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.  

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.  

Ok  cool  –  so  what’s  a  Stream?  

67  

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

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.  

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  

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  

Internal  Itera$on  

72  

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());  

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    

Many  opera$ons  

75  

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

•  Mapping:  map,  flatMap  •  Reducing:  reduce  

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  

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]}      

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  

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  

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  

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!!  

Step  4:  improved  sequen$al  stream  

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

82  

17ms  

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

83  

1ms  

Streams:  much  more  (1)  

84  

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

 

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);      

Create  Op$onal  

86  

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

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);  

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);  

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);  

Op$onal:  default  value  

90  

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

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”;  

Op$onal:  nested  checking  

92  

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

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);  }    

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  

Applica$ons:  Op$onal  methods  

96  

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

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  {    …  }  

 

Applica$ons:  mul$ple  inheritance  

98  

Applica$ons:  mul$ple  inheritance  

99  

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

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);                  }          }  }    

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;            }  }    

Applica$ons:  mul$ple  inheritance  

102  

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).    

Use  case  1  

104  

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();  //  ??          }  }    

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();  //  ??          }  }  

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();  //  ??          }  }  

Use  case  3  

108  

Explicit  disambigua$on  

109  

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

Use  case  4  

110  

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