JDK8(lambda表达式简介)
背景
在Java编码中,经常性的会使用到匿名类,有些时候,这些匿名类非常简单,里面仅包含一个方法,类如Runnable
接口,这种匿名类写起来会非常的难看。其实我们仅仅想把这个唯一的一个方法当做参数传递,在JDK8中,Lambda表达式这个特性就能满足你的这个需求。
From
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello lambda!");
}
});
To
new Thread(() -> System.out.println("hello lambda!"));
语法 一个Lambda表达式包含如下三个部分
参数列表 | 箭头符号 | 函数体 |
---|---|---|
(int x, int y) | -> | x + y |
(int x, int y) -> x + y
() -> 42
(String s) -> { System.out.println(s);
}
第一个参数为x和y,返回x+y的结果
第二个无参,直接返回42
第三个接收一个String类型,并打印出来
一般仅包含一个方法的匿名类,均可以使用lambda表达式的方法书写。
java.util.function包 这里为什么提到这个包呢,因为lambda表达式要求,匿名类中仅有一个未实现的方法,这样才能写成上述的形式,在java.util.function包中,有一些大家较为熟悉的接口,如
- Predicate: 测试一个传入的参数是否符合要求
- Consumer: 消费传入的参数,对传入的参数进行对应的处理
- Function: 对传入的T类型参数转换成R类型的返回
- Supplier: 生成一个T类型的对象,类似Factory方法
- Predicate
可以直接使用
Predicate p =(s)->s.indexOf("a")>-1;
Predicate p1=(s)->s.endsWith("b");
System.out.println(p.test("sda"));
//直接使用p校验
System.out.println(p.and(p1).test("asdb"));
//p和p1两个条件联合校验
或者结合类似
filter
方法使用Optional optional=Optional.of("aaa");
System.out.println(optional.filter(s -> s.indexOf("b")>-1));
- Consumer
Consumer c = s -> System.out.println(s + "aaa");
Consumer c1 = s -> System.out.println(s + "bbb");
c.accept("as");
c.andThen(c1).accept("as");
或者结合类似
Optional
中的ifPresent
使用Optional optional = Optional.of("aaa");
optional.ifPresent(s -> System.out.println(s));
- Function
Function f=s -> Integer.parseInt(s);
System.out.println(f.apply("123"));
或者结合
Optional
中的map
方法使用Optional optional = Optional.of("123");
optional.map(s -> Integer.parseInt(s));
- Supplier
Supplier s= () -> "asd";
System.out.println(s);
Supplier s= () -> "asd";
System.out.println(s);
实现 翻看源码,会发现上述的接口,均使用了
@FunctionalInterface
注解@FunctionalInterface
public interface Consumer {
查看其说明,这个注解仅适用于接口,且要求接口中仅包含一个未实现的方法(默认实现不算在内),若我们的接口中包含1个以上的未实现的方法的时候,编译的时候会提示错误
文章图片
image.png
所以这个
java.util.function
包中的接口简直就是给lambda表达式定制的。
后注 然而,在性能方面,大部分的时候,直接使用lambda表达式的表现并不比传统的写作方式好,例如下面两块代码
for (int i = 0;
i < 10000;
i++) {
optional.filter((s) -> s.indexOf("b") > -1);
}
for (int i = 0;
i < 10000;
i++) {
optional.filter(new Predicate() {
@Override
public boolean test(String s) {
return s.indexOf("b") > -1;
}
});
}
耗费的时间,一个是43,一个是3,相差接近10倍,但是如果我将上面的代码块写成如下
Predicate p = (s) -> s.indexOf("b") > -1;
for (int i = 0;
i < 10000;
i++) {
optional.filter((s) -> s.indexOf("b") > -1);
}
两种的时间消耗就差不多,所以就现在的编译器(本地使用的1.8_111的版本)而言,在lambda上面的优化显然没有传统的匿名类做的好,所以个人有如下几点建议
- 在有大量循环的时候,建议使用传统方式
- 在无性能要求或者相差不大的情况下,当然是lambda
- 当使用到
Stream API
的时候,优先考虑使用parallelStream
并行流来处理 - 现在JDK的版本已经发布到10,后面针对lambda的优化一定会提上日程,所以还是建议大家可以现在开始尝试使用,感受一下函数式变成的魅力
- http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf
- https://www.beyondjava.net/performance-java-8-lambdas
推荐阅读
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- Python爬虫|Python爬虫 --- 1.4 正则表达式(re库)
- oracle|oracle java jdk install
- 正则表达式中增加变量
- sed及正则表达式
- Java8|Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用
- Java正则表达式的应用
- 5.|5. JDK8的并行数据处理
- 制作jdk8|制作jdk8 Dockerfile
- SQL|SQL基本功(五)--函数、谓词、CASE表达式