当前位置:   article > 正文

JDK1.8的新特性大全_jk1.8新特性

jk1.8新特性

JDK1.8的新特性全

1. 前言

JDK1.8已经发布很久了,在很多企业中都已经在使用。并且Spring5、SpringBoot2.0都推荐使用JDK1.8以上版本。所以我们必须与时俱进,拥抱变化。

Jdk8这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。在本文中我们将学习以下方面的新特性:

  • [Lambda表达式](#2. Lambda表达式)
  • [函数式接口](#3. 函数式接口)
  • [方法引用](#4. 方法引用)
  • [接口的默认方法和静态方法](#5. 接口的默认方法和静态方法)
  • [Optional](#6. Optional)
  • [Streams](#7. Streams)
  • [并行数组](#8. 并行数组)

2. Lambda表达式

函数式编程

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。可以使代码变的更加简洁紧凑。

2.1 基本语法:

(参数列表) -> {代码块}
  • 1

需要注意:

  • 参数类型可省略,编译器可以自己推断
  • 如果只有一个参数,圆括号可以省略
  • 代码块如果只是一行代码,大括号也可以省略
  • 如果代码块是一行,且是有结果的表达式,return可以省略

注意:事实上,把Lambda表达式可以看做是匿名内部类的一种简写方式。当然,前提是这个匿名内部类对应的必须是接口,而且接口中必须只有一个函数!Lambda表达式就是直接编写函数的:参数列表、代码体、返回值等信息,用函数来代替完整的匿名内部类

2.2 用法示例

示例1:多个参数

准备一个集合:

// 准备一个集合
List<Integer> list = Arrays.asList(10, 5, 25, -15, 20);
  • 1
  • 2

假设我们要对集合排序,我们先看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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果是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]
  • 1
  • 2
  • 3
  • 4
  • 5

对比一下Comparator中的compare()方法,你会发现:这里编写的Lambda表达式,恰恰就是compare()方法的简写形式,JDK8会把它编译为匿名内部类。是不是简单多了!

别着急,我们发现这里的代码块只有一行代码,符合前面的省略规则,我们可以简写为:

// Jdk8写法
// 因为代码块是一个有返回值的表达式,可以省略大括号以及return
list.sort((i1,i2) -> i1 - i2);
  • 1
  • 2
  • 3
示例2:单个参数

还以刚才的集合为例,现在我们想要遍历集合中的元素,并且打印。

先用jdk1.7的方式:

// JDK1.7遍历并打印集合
for (Integer i : list) {
   
    System.out.println(i);
}
  • 1
  • 2
  • 3
  • 4
  • 5

jdk1.8给集合添加了一个方法:foreach() ,接收一个对元素进行操作的函数:

// JDK1.8遍历并打印集合,因为只有一个参数,所以我们可以省略小括号:
list.forEach(i -> System.out.println(i));
  • 1
  • 2
实例3:把Lambda赋值给变量

Lambda表达式的实质其实还是匿名内部类,所以我们其实可以把Lambda表达式赋值给某个变量。

// 将一个Lambda表达式赋值给某个接口:
Runnable task = () -> {
   
    // 这里其实是Runnable接口的匿名内部类,我们在编写run方法。
    System.out.println("hello lambda!");
};
new Thread(task).start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

不过上面的用法很少见,一般都是直接把Lambda作为参数。

示例4:隐式final

Lambda表达式的实质其实还是匿名内部类,而匿名内部类在访问外部局部变量时,要求变量必须声明为final!不过我们在使用Lambda表达式时无需声明final,这并不是说违反了匿名内部类的规则,因为Lambda底层会隐式的把变量设置为final,在后续的操作中,一定不能修改该变量:

正确示范:

// 定义一个局部变量
int num = -1;
Runnable r = () -> {
   
    // 在Lambda表达式中使用局部变量num,num会被隐式声明为final
    System.out.println(num);
};
new Thread(r).start();// -1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

错误案例:

// 定义一个局部变量
int num = -1;
Runnable r = () -> {
   
    // 在Lambda表达式中使用局部变量num,num会被隐式声明为final,不能进行任何修改操作
    System.out.println(num++);
};
new Thread(r).start();//报错
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3. 函数式接口

经过前面的学习,相信大家对于Lambda表达式已经有了初步的了解。总结一下:

  • Lambda表达式是接口的匿名内部类的简写形式
  • 接口必须满足:内部只有一个函数

其实这样的接口,我们称为函数式接口,我们学过的RunnableComparator都是函数式接口的典型代表。但是在实践中,函数接口是非常脆弱的,只要有人在接口里添加多一个方法,那么这个接口就不是函数接口了,就会导致编译失败。Java 8提供了一个特殊的注解@FunctionalInterface来克服上面提到的脆弱性并且显示地表明函数接口。而且jdk8版本中,对很多已经存在的接口都添加了@FunctionalInterface注解,例如Runnable接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CS1ur467-1585556190296)(runnable.png)]

另外,Jdk8默认提供了一些函数式接口供我们使用:

3.1 Function类型接口

@FunctionalInterface
public interface Function<T, R> {
   
	// 接收一个参数T,返回一个结果R
    R apply(T t);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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类型结果

看出规律了吗?这些都是一类函数接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52914
推荐阅读
相关标签
  

闽ICP备14008679号