Wilder's Blog.

Lambda表达式常见例子

字数统计: 1.5k阅读时长: 6 min
2018/02/12 Share

Lambda 表达式常见例子

用Lambda实现Runnable

使用 ()->{ }代码块代替整个匿名类

1
2
3
4
5
6
7
//不使用Lambda表达式
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
1
2
3
4
5
//使用Lambda表达式
new Thread(()->{
System.out.println("Before Java8, too much code for too little to do");
}).start();
//这里的花括号可以省略,有多个语句时就需要写花括号

如果你的方法接收两个参数,那么可以这么写:

1
2
//可以省略int
(int even,int odd) -> even + odd

用Lambda表达式进行事件处理

1
2
3
4
5
6
7
8
// 不使用Lambda表达式
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");
}
});
1
2
3
show.addActionListener((e)->{
System.out.println("Event handling without lambda expression is boring");
});

用Lambda表达式对列表进行迭代

1
2
3
4
5
// 不使用Lambda表达式
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature);
}
1
2
3
4
5
6
//使用Lambda表达式
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach((n)->System.out.println(n));

//也可以使用Java 8特殊的双引号::
features.forEach(System.out::println);

用lambda表达式和函数式接口Predicate

Predicate 在java.util工具类中,我的理解就是相当于一个判断格式,引用别人博客中的话就是说 使用 java.util.function.Predicate 函数式接口以及lambda表达式,可以向API方法添加逻辑,用更少的代码支持更多的动态行为。

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
public void filter(List<String> list , Predicate<String> condition){
//for(String name:list){
//if(condition.test(name))
// System.out.println(name+" ");
// }

//这里的循环还有更简便的方法,就是采用Stream API中的过滤方法
list.stream().filter((name)->(condition.test(name))).forEach((name)->{
System.out::println
});
}

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

另外,Predicate 接口也允许进行多重条件的测试:

它提供类似于逻辑操作符AND和OR的方法,名字叫做and()、or()和xor(),用于将传入 filter() 方法的条件合并起来。

1
2
3
4
5
6
7
8
//使用了两个Predicate,用and作为连接,表示只有符合这两个条件的元素才会被打印出来    
public static void filter(List<String> languane , Predicate<String> predicate , Predicate<String> predicate2){
languane.stream().filter(predicate.and(predicate2)).forEach(
(name)->{
System.out.println(name+" ");
}
);
}

用Lambda 表达式的Map和Reduce

函数式编程概念map。它允许你将对象进行转换。

1
2
3
4
5
6
7
8
9
10
//不使用Lambda表达式为每个订单加上12%的税
List costBeforeTax = Arrays.asList(100,200,300);
for(Integer cost : costBeforeTax){
double price = cost + 0.12*cost;
System.out.println(price);
}

//使用Lambda表达式
List costBeforeTax = Arrays.asList(100,200,300);
costBeforeTax.stream().map((cost)->cost+0.12*cost).forEach(System.out::println);

Map和Reduce操作是函数式编程的核心操作,因为其功能,reduce 又被称为折叠操作。另外,reduce 并不是一个新的操作,你有可能已经在使用它。SQL中类似 sum()、avg() 或者 count() 的聚集函数,实际上就是 reduce 操作,因为它们接收多个值并返回一个值。流API定义的 reduceh() 函数可以接受lambda表达式,并对所有值进行合并。IntStream这样的类有类似 average()、count()、sum() 的内建方法来做 reduce 操作,也有mapToLong()、mapToDouble() 方法来做转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
//不使用Lambda表达式计算总价和税后价
List costBeforeTax = Arrays.asList(100,200,300);
double total = 0 ;
for(Integer cost : costBeforeTax){
double price = cost + 0.12*cost;
total += price;
}
System.out.println("total = "+total);

//使用Lambda表达式中的reduce计算总价和税后价
List costBeforeTax = Arrays.asList(100,200,300);
double total = costBeforeTax.stream().map((cost)->cost+0.12*cost).reduce((sum , cost) -> sum + cost).get();
System.out.println("total = "+total);

使用dictinct() 方法来对集合进行去重

1
2
3
4
5
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());

//打印number:[9, 10, 3, 4, 7, 3, 4]
//打印distinct:[81, 100, 9, 16, 49]

计算集合元素中的最大值、最小值、总和和平均值

IntStream、LongStream 和 DoubleStream 等流的类中,有个非常有用的方法叫做 summaryStatistics() 。可以返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各种摘要数据。在本例中,我们用这个方法来计算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法来获得列表的所有元素的总和及平均值。

1
2
3
4
5
6
7
//获取数字的个数、最小值、最大值、总和以及平均值
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());

对Lambda 注意的事项

  • Lambda 表达式可以使用方法引用,仅当该方法不会修改Lambda表达式提供的参数;若对参数有任何修改,则必须键入完整的Lambda表达式
1
2
3
4
list.forEach(n -> System.out.println(n)); 
list.forEach(System.out::println); // 使用方法引用

list.forEach((String s) -> System.out.println("*" + s + "*")); //修改字符串s
  • Lambda方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用。
  • lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。
1
2
3
4
5
6
7
List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { factor++; });

//对外部变量factor进行修改,将会出现错误
//但是如果只是访问外部变量而不做修改则被允许
primes.forEach((element)->System.out.println(element*factor) );
CATALOG
  1. 1. Lambda 表达式常见例子
    1. 1.1. 用Lambda实现Runnable
    2. 1.2. 用Lambda表达式进行事件处理
    3. 1.3. 用Lambda表达式对列表进行迭代
    4. 1.4. 用lambda表达式和函数式接口Predicate
    5. 1.5. 用Lambda 表达式的Map和Reduce
    6. 1.6. 使用dictinct() 方法来对集合进行去重
    7. 1.7. 计算集合元素中的最大值、最小值、总和和平均值
    8. 1.8. 对Lambda 注意的事项