赞
踩
JDK1.8已经发布很久了,在很多企业中都已经在使用。并且Spring5、SpringBoot2.0都推荐使用JDK1.8以上版本。所以我们必须与时俱进,拥抱变化。
Jdk8这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。在本文中我们将学习以下方面的新特性:
函数式编程
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。可以使代码变的更加简洁紧凑。
(参数列表) -> {代码块}
需要注意:
return可以省略注意:事实上,把Lambda表达式可以看做是匿名内部类的一种简写方式。当然,前提是这个匿名内部类对应的必须是接口,而且接口中必须只有一个函数!Lambda表达式就是直接编写函数的:参数列表、代码体、返回值等信息,用函数来代替完整的匿名内部类!
准备一个集合:
// 准备一个集合
List<Integer> list = Arrays.asList(10, 5, 25, -15, 20);
假设我们要对集合排序,我们先看JDK7的写法,需要通过匿名内部类来构造一个Comparator:
// Jdk1.7写法
Collections.sort(list,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(list);// [-15, 5, 10, 20, 25]
如果是jdk8,我们可以使用新增的集合API:sort(Comparator c)方法,接收一个比较器,我们用Lambda来代替Comparator 的匿名内部类:
// Jdk1.8写法,参数列表的数据类型可省略:
list.sort((i1,i2) -> {
return i1 - i2;});
System.out.println(list);// [-15, 5, 10, 20, 25]
对比一下Comparator中的compare()方法,你会发现:这里编写的Lambda表达式,恰恰就是compare()方法的简写形式,JDK8会把它编译为匿名内部类。是不是简单多了!
别着急,我们发现这里的代码块只有一行代码,符合前面的省略规则,我们可以简写为:
// Jdk8写法
// 因为代码块是一个有返回值的表达式,可以省略大括号以及return
list.sort((i1,i2) -> i1 - i2);
还以刚才的集合为例,现在我们想要遍历集合中的元素,并且打印。
先用jdk1.7的方式:
// JDK1.7遍历并打印集合
for (Integer i : list) {
System.out.println(i);
}
jdk1.8给集合添加了一个方法:foreach() ,接收一个对元素进行操作的函数:
// JDK1.8遍历并打印集合,因为只有一个参数,所以我们可以省略小括号:
list.forEach(i -> System.out.println(i));
Lambda表达式的实质其实还是匿名内部类,所以我们其实可以把Lambda表达式赋值给某个变量。
// 将一个Lambda表达式赋值给某个接口:
Runnable task = () -> {
// 这里其实是Runnable接口的匿名内部类,我们在编写run方法。
System.out.println("hello lambda!");
};
new Thread(task).start();
不过上面的用法很少见,一般都是直接把Lambda作为参数。
Lambda表达式的实质其实还是匿名内部类,而匿名内部类在访问外部局部变量时,要求变量必须声明为final!不过我们在使用Lambda表达式时无需声明final,这并不是说违反了匿名内部类的规则,因为Lambda底层会隐式的把变量设置为final,在后续的操作中,一定不能修改该变量:
正确示范:
// 定义一个局部变量
int num = -1;
Runnable r = () -> {
// 在Lambda表达式中使用局部变量num,num会被隐式声明为final
System.out.println(num);
};
new Thread(r).start();// -1
错误案例:
// 定义一个局部变量
int num = -1;
Runnable r = () -> {
// 在Lambda表达式中使用局部变量num,num会被隐式声明为final,不能进行任何修改操作
System.out.println(num++);
};
new Thread(r).start();//报错
经过前面的学习,相信大家对于Lambda表达式已经有了初步的了解。总结一下:
其实这样的接口,我们称为函数式接口,我们学过的Runnable、Comparator都是函数式接口的典型代表。但是在实践中,函数接口是非常脆弱的,只要有人在接口里添加多一个方法,那么这个接口就不是函数接口了,就会导致编译失败。Java 8提供了一个特殊的注解@FunctionalInterface来克服上面提到的脆弱性并且显示地表明函数接口。而且jdk8版本中,对很多已经存在的接口都添加了@FunctionalInterface注解,例如Runnable接口:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CS1ur467-1585556190296)(runnable.png)]
另外,Jdk8默认提供了一些函数式接口供我们使用:
@FunctionalInterface
public interface Function<T, R> {
// 接收一个参数T,返回一个结果R
R apply(T t);
}
Function代表的是有参数,有返回值的函数。还有很多类似的Function接口:
| 接口名 | 描述 |
|---|---|
BiFunction<T,U,R> |
接收两个T和U类型的参数,并且返回R类型结果的函数 |
DoubleFunction<R> |
接收double类型参数,并且返回R类型结果的函数 |
IntFunction<R> |
接收int类型参数,并且返回R类型结果的函数 |
LongFunction<R> |
接收long类型参数,并且返回R类型结果的函数 |
ToDoubleFunction<T> |
接收T类型参数,并且返回double类型结果 |
ToIntFunction<T> |
接收T类型参数,并且返回int类型结果 |
ToLongFunction<T> |
接收T类型参数,并且返回long类型结果 |
DoubleToIntFunction |
接收double类型参数,返回int类型结果 |
DoubleToLongFunction |
接收double类型参数,返回long类型结果 |
看出规律了吗?这些都是一类函数接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。