0 引子
学妹:师兄师兄!我去面试被问到 JDK1.8 的新特性这个问题,不知道怎么回答啊!哭了哭了,师兄能帮我总结一下 JDK1.8 的新特性吗?
我:小意思!学妹你先坐下,且让师兄为你慢慢讲解(嘻嘻)
1 前言
了解 JDK1.8 的新特性,无论是面试需要还是工作要求,对我们都是非常重要的,本文会介绍几种 JDK1.8 的新特性,希望能够对大家有所帮助。
2 JDK1.8 特性:Lambda 表达式
Lambda 表达式是一个匿名函数,Lambda 表达式没有声明的方法,也没有访问修饰符、返回值声明和名字,用于帮助我们写出更简洁、更灵活的代码。
Lambda 表达式建立在函数式接口之上,那什么是函数式接口呢?只包含一个抽象方法的接口就被称为函数式接口,我们可以通过 Lambda 表达式来创建函数式接口的对象。
下面我们举个栗子,相信大家经常使用排序功能吧,这里我们使用 Comparator 接口对 Lambda 表达式的使用做一个测试。
我们先使用匿名内部类来实现 Comparator 接口。
public class Test {
public static void main(String[] args){
String[] array = {"apple","string","ss"};
//匿名内部类的使用
Arrays.sort(array,new Comparator
() { @Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
}
}
然后再使用 Lambda 表达式实现 Comparator 接口。
public class Test {
public static void main(String[] args){
String[] array = {"apple","string","ss"};
//使用 Lambda 表达式
Arrays.sort(array, (String s1, String s2) -> (s1.length() - s2.length()));
}
}
可以发现使用 Lambda 表达式更为简洁。
我们之前提到过 Lambda 表达式建立在函数式接口之上,为什么呢?其实是为了保证唯一,我们上面的 Comparator 接口只有一个抽象方法,使用 Lambda 表达式可以代表那个方法,如果接口有多个抽象方法,谁知道 Lambda 表达式代表的是哪一个抽象方法呢?
3 JDK1.8 特性:函数式接口
我们在介绍 Lambda 表达式时其实已经讲得很清楚了,函数式接口是只有一个抽象函数的接口,在 JDK1.8 中提供了@FunctionalInterface 注解来检查函数式接口的合法性。
下面我们介绍几种基础的函数式接口:
Consumer
消费者接口,有参无返回值,用于消费数据。
Consumer 接口中提供了 accept 抽象方法,accept 方法会接受一个变量,即使用该函数式接口时会提供数据,只需接受使用即可。
public class Test {
//使用消费型接口
public static void change(Consumer
con,String str) { con.accept(str);
}
public static void main(String[] args){
change((str) -> System.out.println(str),"Hello World!");
}
}
Function
函数式接口,有参有返回值,提供转换功能。
Function 接口中提供了 apply 抽象方法,apply 接受 T 类型数据并返回 R 类型数据。
public class Test {
//使用函数式接口
public static Integer change(Function
fun,Integer i) { return fun.apply(i);
}
public static void main(String[] args){
Integer num = change((x) -> 2 * x,100);
System.out.println(num);
}
}
Predicate
断言型接口,有参有返回值,其中会返回一个布尔类型的变量,提供断言、判断功能。
Predicate 接口中提供了 test 抽象方法,对传入的数据进行判断,返回 boolean 类型。
public class Test {
//使用断言型接口
public static boolean change(Predicate
pre,String str) { return pre.test(str);
}
public static void main(String[] args){
boolean res = change((str) -> str.equals("Hello"),"Hello");
System.out.println(res);
}
}
Supplier
供给型接口,无参有返回值,用于生产数据。
Supplier 接口中提供了 get 抽象方法,用于返回数据。
public class Test {
//使用供给型接口
public static String change(Supplier
sup) { return sup.get();
}
public static void main(String[] args){
String str = change(() -> "Hello World!");
System.out.println(str);
}
}
函数式接口事实上是为了更加方便地使用 Lambda 表达式,有了 JDK1.8 提供的函数式接口,我们不需要手动创建函数式接口,直接使用即可。
4 JDK1.8 特性:方法引用
我们经常使用 Lambda 表达式来创建匿名方法,但有时我们只是调用一个已经存在的方法而已。在 JDK1.8 中,可以通过方法引用来简写 Lambda 表达式中已经存在的方法。
方法引用是一种更简洁易懂的 Lambda 表达式,其操作符为双冒号 :: 。方法引用是用来直接访问类或者实例的已经存在的方法,它提供了一种引用而不执行方法的方式。
如果 Lambda 表达式仅仅调用一个已存在的方法而不做任何其它事,通过一个方法名字来引用这个已存在的方法也许会更加清晰,Java 8 的方法引用允许我们这样操作。
下面我们举个栗子,对一个 Integer 的封装类进行排序。
Integer 的封装类代码如下:
class NewInteger{
private Integer num;
public NewInteger(Integer num) {
this.num = num;
}
public int getNum() {
return num;
}
public static int compare(NewInteger a,NewInteger b) {
return a.getNum() - b.getNum();
}
}
对其进行排序,我们可以使用匿名内部类写法:
public class Test {
public static void main(String[] args){
NewInteger[] array = {new NewInteger(1),new NewInteger(12),new NewInteger(-1),new NewInteger(34)};
//匿名内部类写法
Arrays.sort(array, new Comparator
() { @Override
public int compare(NewInteger o1, NewInteger o2) {
return o1.getNum() - o2.getNum();
}
});
}
}
我们可以发现,Comparator 是一个函数式接口,故我们可以使用 Lambda 表达式,写法如下:
public class Test {
public static void main(String[] args){
NewInteger[] array = {new NewInteger(1),new NewInteger(12),new NewInteger(-1),new NewInteger(34)};
//Lambda表达式写法
Arrays.sort(array, (NewInteger a,NewInteger b) -> {
return a.getNum() - b.getNum();
});
}
}
其实,我们之前在 Integer 的封装类中已经定义了一个比较方法,因此我们可以直接使用该比较方法:
public class Test {
public static void main(String[] args){
NewInteger[] array = {new NewInteger(1),new NewInteger(12),new NewInteger(-1),new NewInteger(34)};
//Lambda表达式写法
Arrays.sort(array, (a ,b) -> NewInteger.compare(a, b));
}
}
由于 Lambda 表达式调用了一个已存在的方法,因此,我们可以使用方法引用来替代这个 Lambda 表达式。
public class Test {
public static void main(String[] args){
NewInteger[] array = {new NewInteger(1),new NewInteger(12),new NewInteger(-1),new NewInteger(34)};
//方法引用写法
Arrays.sort(array, NewInteger::compare);
}
}
方法引用 NewInteger::compare 与 Lambda 表达式 (a ,b) -> NewInteger.compare(a, b) 是等价的。
方法引用的标准形式是 类名::方法名,一共有四种形式的方法引用,分别为引用静态方法,引用某个对象的实例方法,引用某个类型的任意对象的实例方法,引用构造方法。我们之前所举例子就是一个静态方法引用。
5 JDK1.8 特性:Stream API
由于文章篇幅关系,本文不准备详细介绍 Stream 的各类 API,只会介绍一下 Stream 的概念,并举一个使用 Stream 的小例子,关于 Stream 的各类 API,会在我的下一篇文章为大家一一介绍。
Stream 是一个处理集合的关键抽象概念,可以对集合进行各种操作,Stream API 为我们操作集合提供了强大的功能,同时操作简单,容易上手。
Stream 一般有如下三个操作步骤:
创建 Stream:从一个数据源(集合、数组)中获取流中间操作:一个操作的中间链,对数据源的数据进行操作终止操作:一个终止操作,执行中间操作链,并产生结果
注意,对流的操作完成后需要对其进行关闭。
如何理解 Stream?我们可以这么想,集合的要点在于数据,流的要点在于计算。Stream 既不会存储元素,也不会改变源对象,且会返回一个持有结果的新的 Stream,另外,Stream 的操作是延迟执行的,只有在需要结果时,才会执行。
我们现在实现一个小功能,计算集合中大于 10 的元素数量,在 JDK1.8 之前,我们一般这样实现:
public class Test {
public static void main(String[] args){
List
list = new ArrayList(); list.add(34);
list.add(7);
list.add(2);
list.add(66);
list.add(-3);
list.add(71);
int count = 0;
for (Integer integer : list) {
if(integer > 10) count++;
}
System.out.println("集合中大于10的元素数量:" + count );
}
}
如何使用 Stream API 的话,我们可以这样写代码:
public class Test {
public static void main(String[] args){
List
list = new ArrayList(); list.add(34);
list.add(7);
list.add(2);
list.add(66);
list.add(-3);
list.add(71);
long count = list.stream().filter(i -> i > 10).count();
System.out.println("集合中大于10的元素数量:" + count );
}
}
使用 Stream API 一行代码就解决了,是不是很简单呢!
6 JDK1.8 特性:default 关键字
在 JDK1.8 之前,接口不能提供方法的实现,但在 JDK1.8 之后,我们可以为方法提供默认实现方法和静态方法,分别用关键字 default 和 static 修饰即可。
如果一个类既继承父类又实现接口时,两者方法名相同,类优先;如果实现两个同名方法的接口,则实现类必须手动声明默认实现哪个接口中的方法。
interface Car {
void begin();
//默认实现方法
default void play() {
System.out.println("正在开车");
}
//静态方法
static void end() {
System.out.println("结束开车");
}
}
class Porsche implements Car {
@Override
public void begin() {
System.out.println("保时捷启动");
}
}
public class Test {
public static void main(String[] args){
Car porsche = new Porsche();
porsche.begin();
porsche.play();
Car.end();
}
}
7 总结
JDK1.8 的几个主要新特性我都简单介绍了一下,还有一些别的特性,例如 Optional,Date API 等,由于文章篇幅问题,只能一笔带过。面试能够讲到上面几点,通过应该是没问题的,但在工作中运用却是远远不够。冰冻三尺,非一日之寒,共勉!
————————————————
版权声明:本文为CSDN博主「Geffin」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Geffin/article/details/105069890