Java 8 新特性
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
在本文中我们将围绕以下五点学习(常用的)新特性。并用实际的例子说明在什么场景下适合使用。
友情链接
菜鸟教程:点我跳转Java8新特性菜鸟教程地址
JDK:点我跳转Jdk8官网下载地址
一.Lambda表达式
Lambda 是一个
匿名函数
,我们可以把Lambda表达式理解为是一段可以传递的代码
,将代码像数据一样进行传递。使用它可以写出更简洁,更灵活的代码。作为一种更紧凑的代码风格。使Java的语言表达能力得到了提升。
语法:
(o1,o2) -> Integer.compare(o1,o2);
->
:lambda操作符,也叫箭头操作符-> 左边
:lambda形参列表 (其实就是接口中的抽象方法的形参列表)-> 右边
:lambda体(其实就是重写的抽象方法的方法体)
案例:
- 格式:无参数,无返回值
@Test
public void test(){
//原写法
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("无参无返回值原写法");
}
};
runnable.run();
//Lambda表达式写法
Runnable lrunnable =()->{System.out.println("无参无返回值Lambda表达式写法");};
lrunnable.run();
}
- 格式:Lambda 需要一个参数,但是没有返回值
@Test
public void test(){
//原写法
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("需要一个参数没有返回值,原写法");
//Lambda表达式写法
Consumer<String> lconsumer =(String s)->{System.out.println(s);};
lconsumer.accept("需要一个参数没有返回值,Lambda表达式写法");
}
- 格式:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test
public void test(){
//原写法
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("需要一个参数没有返回值,原写法");
//Lambda表达式写法
Consumer<String> lconsumer =(s)->{System.out.println(s);};
lconsumer.accept("需要一个参数没有返回值并且数据类型可以省略, Lambda表达式写法");
}
- 格式:Lambda 若只需要一个参数时,参数的小括号可以省略
@Test
public void test(){
//原写法
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("需要一个参数没有返回值,原写法");
//Lambda表达式写法
Consumer<String> lconsumer = s ->{System.out.println(s);};
lconsumer.accept("需要一个参数没有返回值,数据类型可以省略,小括号也可以省略 Lambda表达式写法");
}
- 格式:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test
public void test(){
//原写法
Comparator<Integer> comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare(1,2));
//Lambda表达式写法
Comparator<Integer> lcomparator=(o1,o2)->{return o1.compareTo(o2);};
System.out.println(lcomparator.compare(1,2));
}
- 格式:当 Lambda 体只有一条语句时, return 与大括号都可以省略
@Test
public void test(){
//原写法
Comparator<Integer> comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare(1,2));
//Lambda表达式写法
Comparator<Integer> lcomparator=(o1,o2)-> o1.compareTo(o2);
System.out.println(lcomparator.compare(1,2));
}
总结:
- lambda表达式的本质:作为函数式接口的实例
-> 左边
: 如果使用泛型,lambda形参列表的参数类型可以省略(类型推断),如果lambda形参列表只有一个参数()
也可以省略。-> 右边
:lambda体使用一对{}
包裹,如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}
和return
关键字 (如果省略了return关键字{}也一定要去掉) 。
二.函数式(Funcation)接口
如果一个接口中,只声明了一个抽象方法(可以有多个非抽象方法),则此接口就称为函数式接口,函数式接口可以被隐式转换为 lambda 表达式。
学习之前先来看一下JDK 1.8 之前已有的函数式接口 Runnable
我们常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上@FunctionInterface,那么编译器会报错。
自定义函数式接口:
/**
* @author mengzhichao
* @create 2021-06-06-18:25
*/
@FunctionalInterface
public interface MyInterface {
void method();
}
总结:在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例。那么该对象就可以用Lambda表达式来表示。
所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
JDK 1.8 新增加的函数接口:
接口 | 描述 |
---|---|
BiConsumer<T,U> | 代表了一个接受两个输入参数的操作,并且不返回任何结果 |
BiFunction<T,U,R> | 代表了一个接受两个输入参数的方法,并且返回一个结果 |
BinaryOperator< T > | 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
BiPredicate<T,U> | 代表了一个两个参数的boolean值方法 |
BooleanSupplier | 代表了boolean值结果的提供方 |
Consumer | 代表了接受一个输入参数并且无返回的操作 |
DoubleBinaryOperator | 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
DoubleConsumer | 代表一个接受double值参数的操作,并且不返回结果。 |
DoubleFunction< R > | 代表接受一个double值参数的方法,并且返回结果 |
DoublePredicate | 代表一个拥有double值参数的boolean值方法 |
DoubleSupplier | 代表一个double值结构的提供方 |
DoubleToIntFunction | 接受一个double类型输入,返回一个int类型结果。 |
DoubleToLongFunction | 接受一个double类型输入,返回一个long类型结果 |
DoubleUnaryOperator | 接受一个参数同为类型double,返回值类型也为double 。 |
Function<T,R> | 接受一个输入参数,返回一个结果。 |
IntBinaryOperator | 接受两个参数同为类型int,返回值类型也为int 。 |
IntConsumer | 接受一个int类型的输入参数,无返回值 。 |
IntFunction< R > | 接受一个int类型输入参数,返回一个结果 。 |
IntPredicate | 接受一个int输入参数,返回一个布尔值的结果。 |
IntSupplier | 无参数,返回一个int类型结果。 |
IntToDoubleFunction | 接受一个int类型输入,返回一个double类型结果 。 |
IntToLongFunction | 接受一个int类型输入,返回一个long类型结果。 |
IntUnaryOperator | 接受一个参数同为类型int,返回值类型也为int 。 |
LongBinaryOperator | 接受两个参数同为类型long,返回值类型也为long。 |
LongConsumer | 接受一个long类型的输入参数,无返回值。 |
LongFunction< R > | 接受一个long类型输入参数,返回一个结果。 |
LongPredicate | R接受一个long输入参数,返回一个布尔值类型结果。 |
LongSupplier | 无参数,返回一个结果long类型的值。 |
LongToDoubleFunction | 接受一个long类型输入,返回一个double类型结果。 |
LongToIntFunction | 接受一个long类型输入,返回一个int类型结果。 |
LongUnaryOperator | 接受一个参数同为类型long,返回值类型也为long。 |
ObjDoubleConsumer< T > | 接受一个object类型和一个double类型的输入参数,无返回值。 |
ObjIntConsumer< T > | 接受一个object类型和一个int类型的输入参数,无返回值。 |
ObjLongConsumer< T > | 接受一个object类型和一个long类型的输入参数,无返回值。 |
Predicate< T > | 接受一个输入参数,返回一个布尔值结果。 |
Supplier< T > | 无参数,返回一个结果。 |
ToDoubleBiFunction<T,U> | 接受两个输入参数,返回一个double类型结果 |
ToDoubleFunction< T > | 接受一个输入参数,返回一个double类型结果 |
ToIntBiFunction<T,U> | 接受两个输入参数,返回一个int类型结果。 |
ToIntFunction< T > | 接受一个输入参数,返回一个int类型结果。 |
ToLongBiFunction<T,U> | 接受两个输入参数,返回一个long类型结果。 |
ToLongFunction< T > | 接受一个输入参数,返回一个long类型结果。 |
UnaryOperator< T > | 接受一个参数为类型T,返回值类型也为T。 |
案例(再此只演示极个别常用的,小伙伴们私底下可以自行练习):
- consumer即消费接口,传入一个参数,并对其进行相应的操作
public class LambdaTest {
public void happyTime(double money,Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void test(){
//原写法
happyTime(500, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("原写法,价格为:"+aDouble);
}
});
//Lambda表达式写法
happyTime(500,money-> System.out.println("Lambda表达式写法,价格为:"+money));
}
}
- supplier即供给接口,可以传入数据,作为一个容器;
public class LambdaTest {
@Test
public void test(){
//原写法
Supplier<String> supplier=new Supplier<String>() {
@Override
public String get() {
return "原写法,供给型接口";
}
};
System.out.println(supplier.get());
//Lambda表达式写法
Supplier<String> lSupplier=()->"lambda写法,供给型接口";
System.out.println(lSupplier.get());
}
}
- function即方法接口,主要是用作数据类型之间的转换;
public class LambdaTest {
@Test
public void test(){
//原写法(给一个int 转成字符串并返回)
Function<Integer,String> function=new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return String.valueOf(integer);
}
};
System.out.println(function.apply(10).getClass().getName());
//Lambda表达式写法
Function<Integer,String> lFunction=(integer) -> String.valueOf(integer);
System.out.println(lFunction.apply(20).getClass().getName());
}
}
- predicate即判断接口,传入参数,而后返回判断的结果true/false;
public class LambdaTest {
//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> predicate){
List<String> filterList=new ArrayList<>();
for (String s:list){
if (predicate.test(s)){
filterList.add(s);
}
}
return filterList;
}
@Test
public void test(){
//原写法
List<String> list=Arrays.asList(new String[]{"上海", "香港", "澳门", "曹县"});
List<String> filterString = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return "曹县".equals(s) ? true : false;
}
});
System.out.println(filterString);
//Lambda表达式写法
List<String> lfilterString = filterString(list, s -> "上海".equals(s) ? true : false);
System.out.println(lfilterString);
}
}
三.方法引用与构造器引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用 ! 方法引用可以看作是Lambda表达式深层次的表达,换句话说,
方法引用就是Lambda表达式,也就是函数式接口的一个实例
,通过方法名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
语法:
使用操作符 “::” 将类(或对象)与方法名分割开来。
要求:实现接口的抽象方法的参数和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
案例:
- 格式:对象 : : 非静态方法
@Test
public void test(){
//Lambda表达式写法
Consumer<String> consumer = str ->System.out.println(str);
consumer.accept("Lambda表达式");
//方法引用写法
Consumer<String> fConsumer = System.out::println;
fConsumer.accept("方法引用");
}
- 格式:类 : : 静态方法
public class LambdaTest {
@Test
public void test(){
//Lambda表达式写法 比较两个数大小
Comparator<Integer> comparator =(t1,t2) -> Integer.compare(t1,t2);
System.out.println(comparator.compare(10,20));
//方法引用写法
Comparator<Integer> fComparator = Integer::compare;
System.out.println(fComparator.compare(20,10));
}
}
- 格式:类 : : 非静态方法
public class LambdaTest {
@Test
public void test(){
//Lambda表达式写法
Comparator<String> comparator=(s1,s2) -> s1.compareTo(s2);
System.out.println(comparator.compare("abc","abd"));
//方法引用写法
Comparator<String> fComparator = String::compareTo;
System.out.println(fComparator.compare("www","www"));
}
}
正常来说
comparator.compare("abc","abd")
有两个参数,而s1.compareTo(s2)
只有一个参数并不满足上述所说的方法引用的要求。但是为什么能用呢?因为这种情况下,第一个参数作为方法的调用者出现((s1,s2) -> s1.compareTo(s2)
),这种情况下也存在方法引用。只不过这时候我们不是拿具体的对象写,而是拿它的类写(Comparator<String> fComparator = String::compareTo;
)
构造器引用
调用的构造器会根据实现的函数接口的抽象方法的参数列表来确定,如果抽象方法为无参的,则调用的构造器也是无参的。
语法:
ClassName :: new
案例
public class Student {
public Student() {
System.out.println("Student 无参构造已执行");
}
public Student(Integer id) {
System.out.println("Student 有参构造,一个参数.为:"+id);
}
public Student(Integer id, String name, char sex) {
this.id = id;
this.name = name;
this.sex = sex;
}
private Integer id;
private String name;
private char sex;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getsex() {
return sex;
}
public void setsex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
- 通过无参构造器引用(创建对象)
public class LambdaTest {
@Test
public void test(){
//原始写法
Supplier<Student> supplier =new Supplier<Student>() {
@Override
public Student get() {
return new Student();
}
};
supplier.get();
//lambda表达式写法
Supplier<Student> lSupplier =()-> new Student();
lSupplier.get();
//构造器引用写法
Supplier<Student> gSupplier = Student::new;
gSupplier.get();
}
}
- 通过有参构造器引用(一个参数,创建对象)
@Test
public void test(){
//原始写法
Function<Integer,Student> function =new Function<Integer, Student>() {
@Override
public Student apply(Integer integer) {
return new Student(integer);
}
};
function.apply(1);
//lambda表达式写法
Function<Integer,Student> lFunction = id -> new Student(id);
lFunction.apply(2);
//构造器引用写法
Function<Integer,Student> gFunction = Student::new;
gFunction.apply(3);
}
数组引用
大家可以把数组看做是一个特殊的类,写法与构造器引用一致。
public class LambdaTest {
@Test
public void test(){
//原始写法
Function<Integer,String[]> function =new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[integer];
}
};
System.out.println(Arrays.toString(function.apply(10)));
//lambda表达式写法
Function<Integer,String[]> lFunction= length -> new String[length];
System.out.println(Arrays.toString(lFunction.apply(20)));
//构造器引用写法
Function<Integer,String[]> gFunction = String[] :: new;
System.out.println(Arrays.toString(gFunction.apply(30)));
}
}
四.Stream API
Java8中有两大最为重要的改变。第一个是
Lambda表达式
;另外一个则是Stream API
。
Stream API(java.util.Stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API 可以极大提供Java程序员的生产力,让程序员写出高效率,干净,简洁的代码。(Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。)
Strema到底是什么呢?
是数据渠道,用于操作数据源(集合,数组等) 所生成的元素序列。
“集合将的是数据,Stream讲的是计算!”
语法
集合或数组.stream().过滤().映射().终止操作
Stream 操作的三个步骤
创建 Stream
一个数据源(集合,数组),获取一个流中间操作
一个中间操作链,对数据源的数据进行处理终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
注意:
- Stream 自已不会存储元素
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
案例(围绕以上三点进行操作)
首先我们先来了解两个概念
并行流(parallelStream):多个线程同时运行
顺序流(stream):使用主线程,单线程
- Stream 实例化
创建 Stream 方式一:通过集合创建
public class LambdaTest {
@Test
public void test(){
List<Student> students= StudentData.getStudent();
//返回一个顺序流
Stream<Student> stream = students.stream();
//返回一个并行流
Stream<Student> parallelStream = students.parallelStream();
}
}
创建 Stream 方式二:通过数组创建(Java8中的Arrays的静态方法
Stream()
可以获取数组流)
public class LambdaTest {
@Test
public void test(){
int[] arr =new int[]{1,2,3,4,5};
//通过泛型识明你的类型 放进去的是一个int类型的数组,返回的也是int类型的流
IntStream stream = Arrays.stream(arr);
}
}
创建 Stream 方式三:通过Stream的
of()
public class LambdaTest {
@Test
public void test(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
}
}
创建 Stream方式四:创建无限流 (了解)
public class LambdaTest {
@Test
public void test(){
/**
* 例子:遍历前10个偶数并打印出来
* iterate(): 迭代
* seed:种子
* UnaryOperator:函数式接口
* 注意:无限流不加对应的中间操作会无限的进行迭代 limit(10):前10个
*/
Stream.iterate(0, t -> t+2).limit(10).forEach(System.out::println);
}
}
- Stream 中间操作
多个中间操作可以连接起来形成一个 “流水线” ,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次全部处理,成为 “惰性求值”。
筛选与切片 方法 | 描述 |
---|---|
filter(Predicate p) | 接收Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所产生元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流,若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
映射 方法 | 描述 |
map(Funcation f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream |
mapToInt(TolintFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
排序 方法 | 描述 |
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
filter 用法
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//筛选出性别为男的同学信息
students.stream().filter(p-> '男' == p.getsex()).forEach(System.out::println);
}
}
distinct 用法 (去重复数据是通过流所生成元素的
hashCode()
和equals()
所以实体类中需要生成对应的方法)
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//去掉重复的数据
students.stream().distinct().forEach(System.out::println);
}
}
limt 用法
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//展示前三个同学的信息
students.stream().limit(3).forEach(System.out::println);
}
}
skip 用法
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//显示除了前三个之外的学生信息
students.stream().skip(3).forEach(System.out::println);
}
}
map 用法
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//获取到男学生的姓名映射到新的集合中并打印
students.stream().filter(student -> '男'==student.getsex()).map(Student::getName).forEach(System.out::println);
}
}
- Stream 终止操作
终止操作 (终端操作) 从流水线生成结果。其结果可以是任何不是流的值,例如:List,Integer,甚至是 void。
流进行了终止操作后,不能再使用!
匹配与查找 方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素的总个数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代 |
规约 方法 | 描述 |
reduce(T iden,BlnaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 T |
reduce(BlnaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional < T > |
收集 方法 | 描述 |
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
allMatch 方法 (allMatch方法需要所有匹配才会返回true)
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//所有学生是不是都是男生
boolean rst = students.stream().allMatch(student -> '男' == student.getsex());
System.out.println(rst);
}
}
anyMatch 方法 (anyMatch方法只需要一个元素匹配就可以返回true)
public class LambdaTest {
@Test
public void test(){
List<Student> students = StudentData.getStudent();
//是否存在人妖
boolean rst = students.stream().anyMatch(student -> '妖' == student.getsex());
System.out.println(rst);
}
}
reduce 方法
public class LambdaTest {
@Test
public void test(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//计算 1-10 的自然数的和
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
}
}
public class LambdaTest {
@Test
public void test(){
List<Student> students=StudentData.getStudent();
//学生id的总和
Optional<Integer> idSum = students.stream().map(Student::getId).reduce(Integer::sum);
System.out.println(idSum);
}
}
collect 方法 (Collector 对象也有很多可选方法)
public class LambdaTest {
@Test
public void test(){
List<Student> students=StudentData.getStudent();
//查找性别为女的学生并返回一个 list集合
List<Student> list = students.stream().filter(student -> '女' == student.getsex()).collect(Collectors.toList());
System.out.println(list);
}
}
在此只演示个别的方法,小伙伴们私下可自行练习 (^ - ^) !
五.Optional类
Optional<T>
类可以优雅的处理空指针异常。它可以保存T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional
可以更好的表达这个概念。并且可以避免空指针异常。
Optional提供了很多方法,这样我们就不用显式进行空值检测。
【创建实例对象】
创建Optional类对象 方法 | 描述 |
---|---|
of(T t) | 创建一个Optional实例 t 必须非空 |
empty() | 创建一个空的 Optional 实例 |
ofNullable(T t) | t 可以为 null |
通过 of() 方法创建对象,school 不能为空,为空则抛出控制值异常
public class LambdaTest {
@Test
public void test() {
School school=new School();
Optional<School> optionalSchool = Optional.of(school);
}
}
public class LambdaTest {
@Test
public void test() {
School school=new School();
school=null;
Optional<School> optionalSchool = Optional.of(school);
}
}
通过 ofNullable(school) 创建对象,school 可以为空
public class LambdaTest {
@Test
public void test() {
School school=new School();
school=null;
Optional<School> optionalSchool = Optional.ofNullable(school);
System.out.println(optionalSchool);
}
}
【对容器中对象进行操作】
判断Optional容器中是否包含对象 方法 | 描述 |
---|---|
boolean isPresent() | 判断是否包含对象 |
boolean ifPresent(Consumer<? super T> consumer) | 如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它 |
Optional对象的 isPresent() 方法使用
public class LambdaTest {
@Test
public void test() {
School school=new School();
school=null;
Optional<School> optionalSchool = Optional.ofNullable(school);
System.out.println(optionalSchool.isPresent());
}
}
【获取容器的对象】
获取Optional容器的对象 方法 | 描述 |
---|---|
T get() | 如果调用对象包含值,返回该值,否则抛异常 |
T orElse(T other) | 如果有值则将其返回,否则返回指定的other对象 |
T orElseGet(Supplier<? extends T> other) | 如果有值将其返回,否则返回由Supplier接口实现提供的对象 |
T orElseThrow(Supplier<? extends X> exceptionSupplier) | 如果有值将其返回,否则返回由Supplier接口实现提供的异常 |
orElse 方法
public class OptionalTest {
//内部类
public class Student{
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Integer id;
private String name;
}
@Test
public void test(){
String name = getStudentName(new Student(1, "小五"));
System.out.println(name);
}
private String getStudentName(Student student){
//ofNullable()可以接收student为null
Optional<Student> optional = Optional.ofNullable(student);
//如果当前的optional内部封装的student不为空,则返回内部的studetn如果为空,则返回.orElse(new Student(1, "张三"))方法中的参数
return optional.orElse(new Student(1, "张三")).getName();
}
}
public class OptionalTest {
//内部类
public class Student{
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Integer id;
private String name;
}
@Test
public void test(){
String name = getStudentName(null);
System.out.println(name);
}
private String getStudentName(Student student){
//ofNullable()可以接收student为null
Optional<Student> optional = Optional.ofNullable(student);
//如果当前的optional内部封装的student不为空,则返回内部的studetn如果为空,则返回.orElse(new Student(1, "张三"))方法中的参数
return optional.orElse(new Student(1, "张三")).getName();
}
}
如果明确知道数据就是非空可以搭配使用:
of()
+get()
。
如果要避免空指针的话可以搭配使用:ofNullable()
+orElse()
。
总体来说Java8大部分都是语法相关,部分方法没有演示,看完之后一定要多练习,熟能生巧。
最后别忘了一件三连加关注!😊