1. 使用lambda表达式替换匿名类 Lambda表达式语法
1 2 3 (params) -> expression (params) -> statement (params) -> { statements }
如果方法不需要对参数进行任何操作,那么还可以缩写:
1 () -> System.out.println("Hello Lambda Expressions" );
如果方法有两个参数:
实现Runnable接口是匿名类的最好示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void main (String[] args) { CustomOut.out("Lambda表达式允许把函数作为一个方法的参数。" ); try { new Thread(new Runnable() { @Override public void run () { System.out.println("Before Java8, too much code for too little to do!\n" ); } }).start(); new Thread(() -> System.out.println("In Java8, Lambda expression rocks !!\n" )).start(); Thread.sleep(50 ); } catch (InterruptedException e) { e.printStackTrace(); } CustomOut.outEnd(); }
输出
1 2 3 4 5 6 7 8 Before Java8, too much code for too little to do In Java8, Lambda expression rocks !!
2.使用Java 8 lambda表达式进行事件处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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" ); } }); show.addActionListener((e) -> { System.out.println("Light, Camera, Action !! Lambda expressions Rocks" ); }); CustomOut.out("定制Collections.sort()的Comparator" ); ArrayList<Integer> list = new ArrayList<>(); list.add(1 ); list.add(5 ); list.add(3 ); list.add(2 ); list.add(-3 ); list.add(9 ); list.add(0 ); Collections.sort(list, (x, y) -> { return x < y ? 1 : -1 ; }); 9 5 3 2 1 0 -3 */
3.使用lambda表达式对列表进行迭代 1 2 3 4 5 6 7 8 9 10 List list = Arrays.asList("Lambdas" , "Default Method" , "Stream API" , "Date and Time API" ); for (String feature : list) { System.out.println(feature); } list.forEach(n -> System.out.print(n + " " )); System.out.println();
4.使用lambda表达式和函数式接口Predicate 除了在语言层面支持函数式编程风格,Java 8也添加了一个包,叫做 java.util.function。它包含了很多类,用来支持Java的函数式编程。其中一个便是Predicate,使用 java.util.function.Predicate 函数式接口以及lambda表达式,可以向API方法添加逻辑,用更少的代码支持更多的动态行为。下面是Java 8 Predicate 的例子,展示了过滤集合数据的多种常用方法。Predicate接口非常适用于做过滤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public static void main (args[]) { CustomOut.out("使用lambda表达式和函数式接口Predicate" ); List<String> languages = Arrays.asList("Java" , "Scala" , "C++" , "Haskell" , "Lisp" ); System.out.println("Languages which starts with J :" ); filter(languages, (str) -> ((String) str).startsWith("J" )); System.out.println("Languages which ends with a " ); filter(languages, (str) -> ((String) 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) -> ((String) str).length() > 4 ); CustomOut.outEnd(); } public static void filter (List<String> names, Predicate condition) { names.stream().filter((name) -> (condition.test(name))).forEach((name) -> { System.out.println(name + " " ); }); }
5.在lambda表达式中加入Predicate java.util.function.Predicate 允许将两个或更多的 Predicate 合成一个。它提供类似于逻辑操作符AND和OR的方法,名字叫做and()、or()和xor(),用于将传入 filter() 方法的条件合并起来。例如,要得到所有以J开始,长度为四个字母的语言,可以定义两个独立的 Predicate 示例分别表示每一个条件,然后用 Predicate.and() 方法将它们合并起来,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static void filter (List<String> names, Predicate condition) { 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)); }
6.Java 8中使用lambda表达式的Map和Reduce示例 map 本例介绍最广为人知的函数式编程概念map。它允许你将对象进行转换。例如在本例中,我们将 costBeforeTax 列表的每个元素转换成为税后的值。我们将 x -> x*x lambda表达式传到 map() 方法,后者将其应用到流中的每一个元素。然后用 forEach() 将列表元素打印出来。使用流API的收集器类,可以得到所有含税的开销。有 toList() 这样的方法将 map 或任何其他操作的结果合并起来。由于收集器在流上做终端操作,因此之后便不能重用流了。你甚至可以用流API的 reduce() 方法将所有数字合成一个,下一个例子将会讲到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public static void main (String[] args) { CustomOut.out("Java 8中使用lambda表达式的map" ); List<Integer> costBeforeTax = Arrays.asList(100 , 200 , 300 , 400 , 500 ); for (Integer cost : costBeforeTax) { double price = cost + .12 * cost; System.out.println(price); } costBeforeTax = Arrays.asList(100 , 200 , 300 , 400 , 500 ); costBeforeTax.stream().map((cost) -> cost + .12 * cost).forEach(System.out::println); CustomOut.outEnd(); }
reduce 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 List<Integer> 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); 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);
7.通过过滤创建一个String列表 使用lambda表达式和流API过滤大规模数据集合。流提供了一个 filter() 方法,接受一个 Predicate 对象,即可以传入一个lambda表达式作为过滤逻辑。
1 2 3 4 5 6 7 8 9 10 11 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);
另外,关于 filter() 方法有个常见误解。在现实生活中,做过滤的时候,通常会丢弃部分,但使用filter()方法则是获得一个新的列表,且其每个元素符合过滤原则。
8.对列表的每个元素应用函数 我们通常需要对列表的每个元素使用某个函数,例如逐一乘以某个数、除以某个数或者做其它操作。这些操作都很适合用 map() 方法,可以将转换逻辑以lambda表达式的形式放在 map() 方法里,就可以对集合的各个元素进行转换了,如下所示。
1 2 3 4 5 6 7 8 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);
9.复制不同的值,创建一个子列表 如何利用流的 distinct() 方法来对集合进行去重。
1 2 3 4 5 6 7 8 9 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);
10.计算集合元素的最大值、最小值、总和以及平均值 IntStream、LongStream 和 DoubleStream 等流的类中,有个非常有用的方法叫做 summaryStatistics() 。可以返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各种摘要数据。在本例中,我们用这个方法来计算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法来获得列表的所有元素的总和及平均值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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());
CustomOut 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CustomOut { public static void out (String message) { System.err.flush(); System.out.flush(); System.out.println("/*********************************\n" + " * " + message + "\n" + " *********************************/" ); System.err.flush(); System.out.flush(); } public static void outEnd () { System.err.flush(); System.out.flush(); System.out.println("/**************** END **************/\n\n" ); System.err.flush(); System.out.flush(); } }