摘录:http://www.importnew.com/16436.htmlhtml
// Java 8以前: new Thread(new Runnable() { @Override public void run() { System.out.println("Before Java8, too much code for too little to do"); } }).start();
//Java 8方式:用() -> {}代码块替代了整个匿名类 new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
output:java
too much code, for too little to do Lambda expression rocks !!
若是你的方法不对参数进行修改、重写,只是在控制台打印点东西的话,那么能够这样写:shell
() -> System.out.println("Hello Lambda Expressions");
若是你的方法接收两个参数,那么能够写成以下这样:express
若是你的方法接收两个参数,那么能够写成以下这样:
编写事件监听:编程
// Java 8以前: JButton show = new JButton("Show"); show.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Event handling without lambda expression is boring"); } });
// Java 8方式: show.addActionListener((e) -> { System.out.println("Light, Camera, Action !! Lambda expressions Rocks"); });
output:闭包
too much code, for too little to do Lambda expression rocks !!
// Java 8以前: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); for (String feature : features) { System.out.println(feature); }
// Java 8以后: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); features.forEach(n -> System.out.println(n)); // 使用Java 8的方法引用更方便,方法引用由::双冒号操做符标示, // 看起来像C++的做用域解析运算符 features.forEach(System.out::println);
output:ide
Lambdas
Default Method
Stream API
Date and Time API
java.util.function.Predicate 函数式接口以及lambda表达式,能够向API方法添加逻辑,用更少的代码支持更多的动态行为。函数式编程
public static void main(args[]){ List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp"); System.out.println("Languages which starts with J :"); filter(languages, (str)->str.startsWith("J")); System.out.println("Languages which ends with a "); filter(languages, (str)->str.endsWith("a")); System.out.println("Print all languages :"); filter(languages, (str)->true); System.out.println("Print no language : "); filter(languages, (str)->false); System.out.println("Print language whose length greater than 4:"); filter(languages, (str)->str.length() > 4); } public static void filter(List names, Predicate condition) { for(String name: names) { if(condition.test(name)) { System.out.println(name + " "); } } }
output:函数
Languages which starts with J : Java Languages which ends with a Java Scala Print all languages : Java Scala C++ Haskell Lisp Print no language : Print language whose length greater than 4: Scala Haskell
better way:工具
// 更好的办法 public static void filter(List names, Predicate condition) { names.stream().filter((name) -> (condition.test(name))).forEach((name) -> { System.out.println(name + " "); }); }
java.util.function.Predicate 容许将两个或更多的 Predicate 合成一个。它提供相似于逻辑操做符AND和OR的方法,名字叫作and()、or()和xor(),用于将传入 filter() 方法的条件合并起来。
// 甚至能够用and()、or()和xor()逻辑函数来合并Predicate, // 例如要找到全部以J开始,长度为四个字母的名字,你能够合并两个Predicate并传入 Predicate<String> startsWithJ = (n) -> n.startsWith("J"); Predicate<String> fourLetterLong = (n) -> n.length() == 4; names.stream() .filter(startsWithJ.and(fourLetterLong)) .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
也可使用 or() 和 xor() 方法
将 costBeforeTax 列表的每一个元素转换成为税后的值。咱们将 x -> x*x lambda表达式传到 map() 方法,后者将其应用到流中的每个元素。而后用 forEach() 将列表元素打印出来。
// 不使用lambda表达式为每一个订单加上12%的税 List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); for (Integer cost : costBeforeTax) { double price = cost + .12*cost; System.out.println(price); } // 使用lambda表达式 List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
112.0 224.0 336.0 448.0 560.0 112.0 224.0 336.0 448.0 560.0
Map和Reduce操做是函数式编程的核心操做,由于其功能,reduce 又被称为折叠操做。
SQL中相似 sum()、avg() 或者 count() 的汇集函数,实际上就是 reduce 操做,由于它们接收多个值并返回一个值。
流API定义的 reduceh() 函数能够接受lambda表达式,并对全部值进行合并。IntStream这样的类有相似 average()、count()、sum() 的内建方法来作 reduce 操做,也有mapToLong()、mapToDouble() 方法来作转换。
// 为每一个订单加上12%的税 // 老方法: List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); double total = 0; for (Integer cost : costBeforeTax) { double price = cost + .12*cost; total = total + price; } System.out.println("Total : " + total); // 新方法:能够用内建方法,也能够本身定义 List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get(); System.out.println("Total : " + bill);
output:
Total : 1680.0
Total : 1680.0
// 建立一个字符串列表,每一个字符串长度大于2 List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList()); System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);
output:
Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]
// 将字符串换成大写并用逗号连接起来 List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada"); String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", ")); System.out.println(G7Countries);
// 用全部不一样的数字建立一个正方形列表 List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4); List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); System.out.printf("Original List : %s, Square Without duplicates : %s %n", numbers, distinct);
output:
Original List : [9, 10, 3, 4, 7, 3, 4], Square Without duplicates : [81, 100, 9, 16, 49]
ntStream、LongStream 和 DoubleStream 等流的类中,有个很是有用的方法叫作 summaryStatistics() 。能够返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各类摘要数据。
最大值 最小值 全部元素的总和 平均值
//获取数字的个数、最小值、最大值、总和以及平均值 List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29); IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Highest prime number in List : " + stats.getMax()); System.out.println("Lowest prime number in List : " + stats.getMin()); System.out.println("Sum of all prime numbers : " + stats.getSum()); System.out.println("Average of all prime numbers : " + stats.getAverage());
输出:
Highest prime number in List : 29 Lowest prime number in List : 2 Sum of all prime numbers : 129 Average of all prime numbers : 12.9
既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对两者作一个比较分析。
一个关键的不一样点就是关键字 this:
匿名类的 this 关键字指向匿名类,而lambda表达式的 this 关键字指向包围lambda表达式的类。
另外一个不一样点是两者的编译方式:
Java编译器将lambda表达式编译成类的私有方法。使用了Java 7的 invokedynamic 字节码指令来动态绑定这个方法
1)lambda表达式仅能放入以下代码:预约义使用了 @Functional 注释的函数式接口,自带一个抽象函数的方法,或者SAM(Single Abstract Method 单个抽象方法)类型。这些称为lambda表达式的目标类型,能够用做返回类型,或lambda目标代码的参数。例如,若一个方法接收Runnable、Comparable或者 Callable 接口,都有单个抽象方法,能够传入lambda表达式。相似的,若是一个方法接受声明于 java.util.function 包内的接口,例如 Predicate、Function、Consumer 或 Supplier,那么能够向其传lambda表达式。
2)lambda表达式内可使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式能够换为方法引用,由于这仅是一个参数相同的简单方法调用。
list.forEach(n -> System.out.println(n)); list.forEach(System.out::println); // 使用方法引用
然而,若对参数有任何修改,则不能使用方法引用,而需键入完整地lambda表达式,以下所示:
list.forEach((String s) -> System.out.println("*" + s + "*"));
事实上,能够省略这里的lambda参数的类型声明,编译器能够从列表的类属性推测出来。
3)lambda内部可使用静态、非静态和局部变量,这称为lambda内的变量捕获。
4)Lambda表达式在Java中又称为闭包或匿名函数,因此若是有同事把它叫闭包的时候,不用惊讶。
5)Lambda方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用。可使用JDK中的 javap 工具来反编译class文件。使用 javap -p 或 javap -c -v 命令来看一看lambda表达式生成的字节码。大体应该长这样:
private static java.lang.Object lambda$0(java.lang.String);
6)lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7}); int factor = 2; primes.forEach(element -> { factor++; });
Compile time error : "local variables referenced from a lambda expression must be final or effectively final"
另外,只是访问它而不做修改是能够的,以下所示:
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7}); int factor = 2; primes.forEach(element -> { System.out.println(factor*element); })
输出:
4 6 10 14