Java 8 Lambda
最近查找资料学习时,发现例子中有好多地方用到了lambda表达式,所以今天学习记录一下。
推荐一个youtube的视频,讲解的非常不错。国内的伙伴有可能需要fan qiang才能看到。Good luck!!!
https://www.youtube.com/watch?v=gpIUfj3KaOc&list=PLqq-6Pq4lTTa9YGfyhyW2CqdtW9RtY-I3&index=1
Lambda表达式
它可以看做是函数型编程,那么java中函数定义就用接口来担当,所以,用到Lambda的时候需要使用一个接口。Lambda相关的语法规则也在下面代码中补充。
1 public class LamdbaDemo01 { 2 3 public static void main(String[] args) { 4 5 // new Thread( () -> System.out.println("--")).start(); 6 MyLambda greet = () -> System.out.println("Hello World!"); 7 greet.foo(); 8 // MyAdd myAdd = (int i, int j) -> i + j; 9 // 因为参数的变量名称一致,所以参数的变量类型可以省略 10 MyAdd myAdd = (i, j) -> i + j; 11 System.out.println(myAdd.add(2, 3)); 12 13 // 当参数只有一个的时候可以省略() , 此外当箭头右侧的代码只用一行的时候,可以省略{} 14 MyLength myLength = s -> s.length(); 15 System.out.println(myLength.leng("Hello world!")); 16 } 17 } 18 19 // 接口中只能有一个方法,这是使用Lambda表达式的要求 20 interface MyLambda { 21 void foo(); 22 } 23 24 interface MyAdd { 25 int add(int i, int b); 26 } 27 28 interface MyLength { 29 int leng(String s); 30 }
接下来看一个例子:
1 public interface Condition { 2 boolean test (Person p); 3 }
1 import java.util.Arrays; 2 import java.util.Collections; 3 import java.util.Comparator; 4 import java.util.List; 5 6 public class Unit1ExercistWithJava7 { 7 8 public static void main(String args[]) { 9 10 List<Person> list = Arrays.asList( 11 new Person ("Charles", "Dickens", 60), 12 new Person ("Lewis", "Carrol", 42), 13 new Person ("Thamos", "Cayloe", 51), 14 new Person ("Charlotte", "Brote", 45), 15 new Person ("Matthew", "Aroid", 39) 16 ); 17 18 // step 1: sort list by lastName 19 Collections.sort(list, new Comparator<Person>(){ 20 @Override 21 public int compare(Person o1, Person o2) { 22 return o1.getLastName().compareTo(o2.getLastName()); 23 } 24 } ); 25 26 // step 2: Create a method that print all elements in the list 27 printConditionally (list, new Condition(){ 28 @Override 29 public boolean test(Person p) { 30 return true; 31 } 32 }); 33 34 System.out.println("-------------------------"); 35 // step 3: Create a method that prints all people whose lastName beginning whie C 36 printConditionally(list, new Condition(){ 37 @Override 38 public boolean test(Person p) { 39 return p.getLastName().startsWith("C"); 40 } 41 }); 42 } 43 44 private static void printConditionally (List<Person> list, Condition condition) { 45 for (Person p : list) { 46 if (condition.test(p)) { 47 System.out.println(p); 48 } 49 } 50 } 51 }
上面的例子很简单,就是创建一个接口,里面有test方法,之后创建了一个List,根据自己的需要将list中满足一定条件的值取出。这里例子是用Java7写的。
接下来看Lambda表达式的例子:
1 import java.util.Arrays; 2 import java.util.Collections; 3 import java.util.List; 4 5 public class Unit1ExercistWithLambda { 6 7 public static void main(String args[]) { 8 9 List<Person> list = Arrays.asList( 10 new Person ("Charles", "Dickens", 60), 11 new Person ("Lewis", "Carrol", 42), 12 new Person ("Thamos", "Cayloe", 51), 13 new Person ("Charlotte", "Brote", 45), 14 new Person ("Matthew", "Aroid", 39) 15 ); 16 17 // step 1: sort list by lastName 18 // 使用Lambda表达式时,刚开始写不出,可以先写出匿名类的形式,之后在这个基础上再进行修改,慢慢的就会写了 19 // 为什么括号里直接省略掉参数类型,你尅看用Java8实现的例子 20 Collections.sort(list, (p1, p2) -> p1.getLastName().compareTo(p2.getLastName())); 21 22 // step 2: Create a method that print all elements in the list 23 printConditionally (list, (p) -> true); 24 25 System.out.println("-------------------------"); 26 // step 3: Create a method that prints all people whose lastName beginning whie C 27 printConditionally(list, (p) -> p.getLastName().startsWith("C")); 28 } 29 30 private static void printConditionally (List<Person> list, Condition condition) { 31 for (Person p : list) { 32 if (condition.test(p)) { 33 System.out.println(p); 34 } 35 } 36 } 37 }
在这个例子中,条件判断的实现,通过Lambda表达式来实现,可以看到代码量的减少,这是它的一个好处。
我们现在思考一下使用Lambda表达式的步骤。首先需要有个接口,接口中,必须有且只有一个方法,这是使用Lambda的前提条件。
之后,你就可以编写接口的实现部分。
其实我们也可以不自己创建接口,使用java.util.function 包 里面存在的接口。
比如上面Lambda表达式的例子可以修改成如下:
1 private static void printConditionally (List<Person> list, Predicate<Person> predict) { 2 for (Person p : list) { 3 if (predict.test(p)) { 4 System.out.println(p); 5 } 6 } 7 }
这样的话,接口虽然修改了,但是Lambda实现的部分,完全不用任何修改,这是Lambda的另一个优势。
我们还在可以在printConditionally方法中再添加一个功能接口,例子如下:
1 // step 2: Create a method that print all elements in the list 2 printConditionally (list, (p) -> true, (p) -> System.out.println(p)); 3 4 System.out.println("-------------------------"); 5 // step 3: Create a method that prints all people whose lastName beginning whie C 6 printConditionally(list, (p) -> p.getLastName().startsWith("C"), (p) -> System.out.println(p)); 7 } 8 9 private static void printConditionally (List<Person> list, Predicate<Person> predict, Consumer<Person> consumer) { 10 for (Person p : list) { 11 if (predict.test(p)) { 12 consumer.accept(p); 13 } 14 } 15 }
个人感受是,Lambda表达式使代码解耦,提高结构的灵活性。
Exception的捕获
无例子不说话:
1 import java.util.function.BiConsumer; 2 3 public class Unit1ExercistWithLambdaWithException { 4 5 public static void main(String args[]) { 6 int [] someNumbers = {1,2,3,4}; 7 int key = 0; 8 /*第二种设想是在 process 方法中的第三个参数外侧添加try catch 9 但是那样的话,跟java 7的匿名类有些相似,而且,又会增加耦合度。 10 最后,使用现在的,第三种方式来捕获异常。可能会觉得麻烦,跟之前的两种方法没什么区别, 11 但是第三种方式,我觉得有些像AOP,而且这样对结构的入侵要少*/ 12 process (someNumbers, key, wrapperLambda((k ,v) -> System.out.println(k/v))); 13 } 14 15 private static BiConsumer<Integer, Integer> wrapperLambda(BiConsumer<Integer, Integer> wrapper) { 16 return (k ,v) -> { 17 try { 18 wrapper.accept(k, v); 19 } catch (ArithmeticException e) { 20 System.out.println("Exception caught in wrapper lambda"); 21 } 22 }; 23 } 24 25 private static void process(int[] someNumbers, int key, BiConsumer<Integer, Integer> consumer) { 26 // Exception的捕捉的第一种设想是在下面代码块的外侧追加try catch 来捕捉异常 27 // 但是,这只是个抽象的process的方法,不能确定实现类中出现的异常,所以在这里捕捉,不合理 28 for (int i : someNumbers) { 29 consumer.accept(i, key); 30 } 31 } 32 }
不知道怎么该如何讲述这个部分,例子有注释,大家不懂的地方,再留言谈论。
方法的引用
例子如下:
1 public class MethodReference { 2 3 public static void main(String[] args) { 4 5 // 下面两行的代码是等价的 6 // Thread thread = new Thread(() -> printMessage()); 7 Thread thread = new Thread(MethodReference::printMessage); 8 thread.start(); 9 } 10 11 private static void printMessage() { 12 System.out.println("Hello World!"); 13 } 14 15 }
Unit1ExercistWithLambda3.java 中的例子中的部分代码:
1 // printConditionally(list, (p) -> p.getLastName().startsWith("C"), (p) -> System.out.println(p)); 2 3 printConditionally(list, (p) -> p.getLastName().startsWith("C"), System.out::println);
foreach
1 import java.util.Arrays; 2 import java.util.List; 3 4 public class CollectionIterationExample { 5 6 public static void main(String[] args) { 7 List<Person> list = Arrays.asList( 8 new Person ("Charles", "Dickens", 60), 9 new Person ("Lewis", "Carrol", 42), 10 new Person ("Thamos", "Cayloe", 51), 11 new Person ("Charlotte", "Brote", 45), 12 new Person ("Matthew", "Aroid", 39) 13 ); 14 15 System.out.println("Using for loop"); 16 for (int i=0; i<list.size();i++) { 17 System.out.println(list.get(i)); 18 } 19 20 System.out.println("Using for each loop"); 21 for (Person person : list) { 22 System.out.println(person); 23 } 24 25 // Java8 Lambda 26 System.out.println("Using for loop"); 27 list.forEach(p -> System.out.println(p)); 28 System.out.println("--------------"); 29 list.forEach(System.out::println); 30 } 31 32 }
Stream
1 public class StreamExcample { 2 3 public static void main(String[] args) { 4 5 List<Person> list = Arrays.asList( 6 new Person ("Charles", "Dickens", 60), 7 new Person ("Lewis", "Carrol", 42), 8 new Person ("Thamos", "Cayloe", 51), 9 new Person ("Charlotte", "Brote", 45), 10 new Person ("Matthew", "Aroid", 39) 11 ); 12 13 System.out.println("-------------------------"); 14 list.stream() 15 .filter(p -> p.getLastName().startsWith("C")) 16 .forEach(p -> System.out.println(p)); 17 System.out.println("-------------------------"); 18 long count = list.stream() 19 .filter(p -> p.getFirstName().startsWith("M")) 20 .count(); 21 System.out.println(count); 22 } 23 } 24 25 26 ------------------------- 27 firstName :Lewis lastName :Carrol age 42 28 firstName :Thamos lastName :Cayloe age 51 29 ------------------------- 30 1
里面的Stream等一些8中新出现的东西还是蛮有趣的,以后编码时会尝试使用,棒棒的!
推荐看篇头推荐的那个youbute的链接视频,very excellent for tutorials of Lambda