Lambda表达式
Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段传递代码(将代码像数据一样进行传递)。
使用它可以写出更简洁,跟灵活的代码。
作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda表达式的使用
1. 举例:
2. 格式:
-> :lambda操作符或箭头操作符
-> 左边:lambda形参列表(其实就是接口中的抽象方法的形参列表)
-> 右边:lambda体(其实就是重写的抽象方法的方法体)
3. Lambda表达式的使用:(分为6种情况)
-1. lambda没有参数,也没有返回值
@Test
public void show01(){
Runnable runnable= new Runnable() {
@Override
public void run() {
System.out.println("武汉加油!");
}
};
runnable.run();
Runnable r2 = () -> System.out.println("中国加油!");
r2.run();
}
-2. lambda需要一个参数,但没有返回值
@Test
public void show03(){
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("武汉挺住!");
Consumer<String> c1=(String s)-> {
System.out.println(s);
};
c1.accept("中国挺住!");
}
-3.语法格式三:数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
@Test
public void show03(){
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("武汉挺住!");
Consumer<String> c1=(s)-> {System.out.println(s);};
c1.accept("中国挺住!");
}
-4. 若只需要一个参数时,小括号可以省略:
@Test
public void show04(){
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("武汉挺住!");
Consumer<String> c1=(s)-> System.out.println(s);
c1.accept("中国挺住!");
}
-5.需要两个或两个以上的参数,多条执行语句,并且可以有返回值。
@Test
public void show05(){
Comparator<Integer> comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1+o2;
}
};
System.out.println(comparator.compare(3, 4));
/*Lambda表达式的写法*/
Comparator<Integer> c4=(o1,o2)->{
System.out.println("----------");
System.out.println("----------");
return o1.compareTo(o2);
};
System.out.println(c4.compare(4, 3));
}
-6. 有参数,但只有一条语句,可以有返回值。
@Test
public void show04(){
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("武汉挺住!");
Consumer<String> c1=(s)-> System.out.println(s);
c1.accept("中国挺住!");
}
总结:
-> 左边:lambda形参列表的参数类型可以省略;如果参数列表只有一个参数,其一对小括号可以省略
-> 右边:lambda体应该使用一对{}包裹,如果只有一条执行语句,那么可以省略这一对{}以及return关键字
4. Lambda表达式的本质:接口的实例。
函数式接口
什么是函数式(Functionall)接口:
1. 只包含一个抽象方法的接口,称为函数式接口。
2. 可以通过Lambda表达式来创建该接口的对象。若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明。
3. 我们可以在要给接口上使用@Functionallnterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
4. 在java.util.function包下定义了java8的丰富的函数式接口。
Java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer 消费型接口 | T | void | 对类型为T的对象应用操作,包含方法,void accept(T t) |
Supplier 供给型接口 | 无 | T | 返回类型为T的对象,包含方法: T get() |
Function<T,R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate 断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法boolean test(T t) |
示例:
'Consumer<T>':
@Test
public void show05(){
happyTime(400,money-> System.out.println(money));
}
public void happyTime(double money,Consumer<Double> consumer){
consumer.accept(money);
}
'Predicate<T>':
@Test
public void show06(){
List<String> strings = Arrays.asList("北京", "南京", "天津", "南京", "东京");
List<String> jin = filterString(strings, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("京");
}
});
System.out.println(jin);
/*使用Lambda表达式*/
List<String> jing = filterString(strings, s -> s.contains("京"));
System.out.println(jing);
}
public List<String> filterString(List<String> list, Predicate<String> predicate){
ArrayList<String> filterList=new ArrayList<>();
for (String s:list){
if (predicate.test(s)){
filterList.add(s);
}
}
return filterList;
}
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T,U,R> | T,U | R | 对类型为T,U参数应用操作,返回R类型的结果。包含方法为:R apply(T t,U u); |
UnaryOperator (Function子接口) | T | T | 对类型为T的对象进行一次元运算,并返回T类型的结果。包含方法为:T apply(T t); |
BinaryOperator (BiFunction子接口) | T,T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为: T apply(T t1,T t2); |
BiConsumer<T,U> | T,U | void | 对类型为T,U参数应用操作。 |
BiPRedicate<T,U> | T,U | boolean | 包含方法为:boolean test(T t,U u); |
ToIntFunction TLongFunction ToDoubleFunction | T | int long double | 分别计算int,long,double值的函数 |
IntFunction LongFunction DoubleFunction | int long double | R | 参数分别为int, long ,double 类型的参数 |
何时使用函数式接口
如果开发中需要我们自定义一个函数式接口,首先查看jdk中自带的是否能满足实际情况的函数式接口。如果有则直接调用即可。
方法引用与构造器引用
1. 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
2. 方法引用可以看做式Lambda表达式深层的表达。换句话说,方法引用是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
3. 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
4. 如下三种主要使用情况:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法形参列表和返回值类型相同!
示例代码:
/**
* 方法引用的使用
*使用情景:
* 要传给lambda体的操作,已经有方法实现了就可以使用方法引用
* 方法引用本质上就是lambdaa表达式,而lambda表达式是接口的实例,所以方法引用就是接口的实例
* @Author MH
* @Date 2020/1/31 22:29
*/
public class TestEmployee {
/**
* 情况一:
* 对象::实例方法
* Consumer中的void accept(T t)
* PrintStream中的void print(T t)
*/
@Test
public void show1() {
Consumer<String> c1=(s)-> System.out.println(s);
c1.accept("背景");
/************************/
PrintStream out = System.out;
Consumer<String> c2=out::print;
c2.accept("背景");
}
/**
* 对象::实例方法
* Supplier中的T get()
* Employee中的String getName()
*/
@Test
public void show2() {
Employee emp=new Employee(3,23,"张三",343);
Supplier<String> sup1 = () -> emp.getName();
System.out.println(sup1.get());
/**********************************************/
Supplier<Double> sup2 = emp::getSalary;
System.out.println(sup2.get());
}
/**
* 情况二:
* 类::静态方法
* Comparator中的int compare(T t1,T t2)
* Integer中int compare(int t1,int t2);
*/
@Test
public void show3() {
Comparator<String > s=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
//----------------lambda---------------------
Comparator<String> com1=(c1,c2)-> Integer.parseInt(c1)+Integer.parseInt(c2);
System.out.println(com1.compare("3","3"));
// ----------------方法引用---------------------
Comparator<Integer> com2=Integer::compare; //两个数相比较
System.out.println(com2.compare(3, 3));
}
/**
* 情况二:
* 类::静态方法
* Function中的R apply(T t)
* Math 中的Long round(Double d)
*/
@Test
public void show4() {
Function<Double,String> f=new Function<Double, String>() {
@Override
public String apply(Double integer) {
return String.valueOf(Math.round(integer));
}
};
Function<Integer, String> f1 = (s) -> s.toString()+",纳尼";
System.out.println(f1.apply(34));
// -----------------
Function<Double, Double> f2=Math::ceil; //根据round的类型来定义泛型类型
System.out.println(f2.apply(44.1));
}
/**
* 情况三:
* 类::实例方法
* Comparator 中int compare(T t1,T t2)
* String 中int t1.compareTo(t2)
*/
@Test
public void show5() {
Comparator<String> c=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return 0;
}
};
// --------------------------
Comparator<String> c2=(s1,s2)->s1.compareTo(s2);
System.out.println(c2.compare("a", "b"));
//---------------------------
Comparator<String> c3 = String::compareTo;
System.out.println(c3.compare("a", "b"));
}
/**
* 情况三:
* 类::实例方法
* BiPredicate中的boolean test(T t1,T t2);
* String 中boolean t1.equals(t2)
*/
@Test
public void show6() {
BiPredicate<String,String> b=String::equals;
System.out.println(b.test("a", "b"));
}
/**
* Function中R apply(T t)
* Employee中String getName(T t)
*/
@Test
public void show7() {
Function<Employee,String> f=Employee::getName;
String name = f.apply(new Employee(1, 23, "扎根三", 34.3));
System.out.println(name);
}
}
使用建议
如果给函数式接口提供实例,恰好满足方法引用的使用情景,这时就可以考虑使用方法引用给函数式接口提供实例
构造器引用
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。抽象方法的返回值类型为构造器所属的类的类型。
示例:
/**
* Supplier中的T get()
*/
@Test
public void test1(){
Supplier<Employee> s=new Supplier<Employee>() {
@Override
public Employee get() {
return null;
}
};
// ------------
Supplier<Employee> s1 = () -> new Employee();
System.out.println(s1.get());
Supplier<Employee> s2 = Employee::new;
System.out.println(s2.get());
}
/**
* Function中的R apply(T t);
*/
@Test
public void test2(){
Function<Integer, Employee> f = Employee::new;
System.out.println(f.apply(3));
}
/**
* BiFunction中的R apply(T t,U u);
*/
@Test
public void test3(){
BiFunction<Integer, String, Employee> b = Employee::new;
System.out.println(b.apply(3, "阿斯"));
}
数组引用
可以把数组看作是一个特殊的类,则写法与构造器引用一致
示例:
/**
* 数组引用
* Function中的R apply(T t)
*/
@Test
public void test4() {
Function<Integer,String[]> fun=new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[0];
}
};
// --------------------------------------
Function<Integer, String[]> f = (i) -> new String[i];
System.out.println(Arrays.toString(f.apply(4)));
//---------------------------------------------
Function<Integer, String[]> f1 = String[]::new;
System.out.println(Arrays.toString(f.apply(4)));
}
强大的Stream API
StreamAPI说明
1. java8中有两大最为重要的改变。第一是Lambda表达式;另一个是Stream API.
2. Stream API(java.util.stream)把真正的函数式编程的风格引入到Java中。
这是目前位置对Java类库最好的补充,因为Stream API可以极高Java程序员的生产力,让程序员写出高效率,干净,简洁的代码。
3. Stream 是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据等操作。
使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。
也可以使用Stream API来进行执行操作。
简言之,Stream API提供了一种高效且易于使用的处理数据的方式。
Stream的操作三个步骤
- 创建Stream
一个数据库(如集合,数组),获取一个流
- 中间操作
一个中间操作链,对数据源的数据进行处理
- 终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。之后不会在被使用。
创建Stream方式一:通过集合
Java8中的Collection接口被扩展,提供了两个获取流的方法:
1. default Stream<E> stream():返回一个顺序流
2. default Stream<E> parallelStream():返回一个并行流
示例:
@Test
public void show1(){
List<Employee> employees = EmployeeDate.getEmployees();
Stream<Employee> stream = employees.stream(); //顺序流
Stream<Employee> employeeStream = employees.parallelStream();//并行流
}
创建Stream方式二:通过数组
Java8中Arrays的静态方法stream()可以获取数组流:
- static <T> Stream<T> stream(T[] array):返回一个流
重载形式,能够处理对应基本类型的数组:
- public static IntStream stream(int[] array)
- public static LongStream stream(long[] array)
- public static DoubleStream stream(double[] array)
/**
* 创建Stream方式二:
* 数组
*/
@Test
public void show2(){
int[] i = new int[]{1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(i);
//自定义数组
Employee e=new Employee(1,"zs");
Employee e2 = new Employee(2, "ls");
Employee[] es=new Employee[]{e,e2};
Stream<Employee> stream1 = Arrays.stream(es);
}
创建Stream方式三:通过Stream的of()
/**
* 创建Stream方式三:
* 通过Stream的of();
*/
@Test
public void show3() {
Stream<Integer> integerStream = Stream.of(1, 2, 3);
}
创建Stream方式四:创建无限流
可以使用静态方法Stream.iterate()和Stream.generate(),创建无限流
- 迭代:
public static <T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
-生成
public static <T> Stream<T> generate(Supplier<T> s);
@Test
public void show4() {
//便利前10个偶数
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
Supplier<Integer> supplier= new Supplier<Integer>() {
@Override
public Integer get() {
return null;
}
};
System.out.println("-----------------");
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,
否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,成为"惰性求值"
- 筛选切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成的元素hashCode()和equals()去除重复元素 |
limit(long maxSize) | 截断流,时期元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个则返回一个空流。与limit(n)互补 |
示例:
@Test
public void show1(){
List<Employee> employees = EmployeeDate.getEmployees();
employees.forEach(e->System.out.println(e));
System.out.println("----------顺序流----------");
Stream<Employee> stream = employees.stream(); //顺序流
System.out.println("----------并行流----------");
Stream<Employee> employeeStream = employees.parallelStream();//并行流
System.out.println("------------filter:过滤----------------");
stream.filter(e -> e.getSalary() > 300).forEach(System.out::println);
employeeStream.filter(e->e.getAge()>22).forEach(System.out::println);
System.out.println("---------skip:跳过前几条---------");
employees.stream().skip(2).forEach(System.out::println);
System.out.println("------------distinct:筛选,去除重复元素(重写equals和hashcode)--------------- ");
employees.stream().distinct().forEach(System.out::println);
List<String> strings = Arrays.asList("1", "1", "2", "2", "3");
strings.stream().distinct().forEach(System.out::println);// 1 2 3
}
//注:forEach()属于终止操作。。
- 映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该参数会被应用到每个元素上,并将其映射成一个新的元素。 |
map ToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream. |
map ToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream |
map ToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream. |
flatMap(Function f) | 接收一个函数作为参数,将流中的值换成另外一个流,然后把所有流连接成一个流。 |
示例:
@Test
public void show02(){
List<String> strings = Arrays.asList("aa", "bb", "cc");
List<String> str1 = Arrays.asList("Dd", "ee", "ff");
Stream<String> stream = strings.stream();
/*map*/
stream.map(s -> s.toUpperCase().substring(1)).forEach(System.out::println);
/*获取长度大于3的员工姓名*/
List<Employee> employees = EmployeeDate.getEmployees();
employees.stream().map(s -> s.getName()).filter(s -> s.length() > 2).forEach(System.out::println);
/*flatMap()*/
Stream<String> stream1 = str1.stream();
stream1.flatMap(StreamAPITest1::formStringStream).forEach(System.out::println);
}
public static Stream<Character> formStringStream(String s){
List<Character> list=new ArrayList<>();
for (Character l:s.toCharArray()){
list.add(l);
}
return list.stream();
}
- 排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
示例:
@Test
public void show04(){
List<Integer> integers = Arrays.asList(1, 435, 34, 4543, 34, 234, 34);
/*sorted:顺序排序*/
integers.stream().sorted().forEach(System.out::println);
List<Employee> employees = EmployeeDate.getEmployees();
Stream<Employee> stream = employees.stream();
/*sorted(Comparator m)定制排序*/
stream.sorted((o1,o2)->Integer.compare(o1.getAge(),o2.getAge())).forEach(System.out::println);
}
Stream的终止操作
- 终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List,Integer,甚至是void.
- 流进行了终止操作后,不能再次使用
1- 匹配与查找
方法 | 描述 |
---|---|
allMatch(Prediccate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户去做迭代称为外部迭代。相反,StreamAPI使用内部迭代) |
示例:
@Test
public void show01(){
List<Employee> employees = EmployeeDate.getEmployees();
Stream<Employee> stream = employees.stream();
Predicate<Employee> p=new Predicate<Employee>() {
@Override
public boolean test(Employee employee) {
return false;
}
};
/*allMatch:所有的是否符合*/
//判断年龄是否都大于18
boolean b = stream.allMatch(employee -> employee.getAge() > 18);
System.out.println(b);
/*anyMatch:只要有一个符合就返回true*/
boolean b1 = employees.stream().anyMatch(employee -> employee.getAge() > 23);
System.out.println(b1);
/*noneMatch:是否没有匹配的元素
* startsWith(n):是否以n开头
* */
boolean l = employees.stream().noneMatch(e -> e.getName().startsWith("李"));
System.out.println(l);
/*findFirst:返回第一个元素*/
Optional<Employee> first = employees.stream().findFirst();
System.out.println(first);
/*findAny:返回任意一个*/
Optional<Employee> any = employees.stream().findAny();
System.out.println(any);
/*count:返回总数*/
long count = employees.stream().filter(e->e.getSalary()>300).count();
System.out.println(count);
/*max:返会最大的数*/
Optional<Employee> max = employees.stream().max(Comparator.comparingDouble(Employee::getSalary));
System.out.println(max);
/*min:返回最小的*/
Optional<Employee> min = employees.parallelStream().min(Comparator.comparingInt(Employee::getAge));
System.out.println(min);
/*forEach()*/
employees.parallelStream().forEach(System.out::println);
}
2- 规约
方法 | 描述 |
---|---|
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来得到一个值。返回Optional |
备注:map和reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名。
示例:
@Test
public void show2(){
List<Integer> integers = Arrays.asList(23, 34, 3, 34, 5);
Integer reduce = integers.stream().reduce(0, Integer::sum);
System.out.println(reduce);
//计算公司所有员工工资总和
List<Employee> employees = EmployeeDate.getEmployees();
Stream<Employee> employeeStream = employees.parallelStream();
// Stream<Double> doubleStream = employeeStream.map(employee -> employee.getSalary());
Stream<Double> doubleStream = employeeStream.map(Employee::getSalary);
Double reduce1 = doubleStream.reduce(0d, Double::sum);
System.out.println("工资总和:"+reduce1);
}
3-收集
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于stream中元素做汇总的方法 |
Collector 接口方法的实现绝对了如何对流执行收集的操作(如收集到List,Set,Map).
另外,Collectors实用类提供了很多静态方法,可以方便的创建常见收集器实例,具体方法与实例如下表:
方法 | 返回类型 | 作用 | 示例 |
---|---|---|---|
toList | List | 把流中元素收集到List | list.stream().collect(Collectors.toList()); |
toSet | Set | 把流中元素收集到Set | list.stream().collect(Collectors.toSet()); |
toCollection | Collection | 把流中的数据收集到创建的集合 | employees.parallelStream().collect(Collectors.toCollection(ArrayList::new)); |
counting | Long | 计算流中元素的个数 | employees.parallelStream().collect(Collectors.counting()); |
summingInt | Integer | 对流中元素的整数属性求和 | employees.parallelStream().collect(Collectors.summingDouble(Employee::getSalary)); |
averagingInt | Double | 计算流中元素Integer属性的平均值 | employees.parallelStream().collect(Collectors.averagingInt(Employee::getAge)); |
summarizingInt | IntSummaryStatistics | 收集流中Integer属性的统计值。如平均 | employees.parallelStream().collect(Collectors.summarizingInt(Employee::getAge)); |
示例:
@Test
public void show4(){
List<Employee> employees = EmployeeDate.getEmployees();
Stream<Employee> employeeStream = employees.parallelStream();
Set<Employee> collect = employeeStream.collect(Collectors.toSet());
collect.forEach(System.out::println);
System.out.println("------------------------------");
ArrayList<Employee> collect1 = employees.parallelStream().collect(Collectors.toCollection(ArrayList::new));
collect1.forEach(System.out::println);
System.out.println("----counting()------------");
Long collect2 = employees.parallelStream().collect(Collectors.counting());
System.out.println("总条数:" + collect2);
System.out.println("-------------summingDouble-------------");
Double collect3 = employees.parallelStream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println("总金额:"+collect3);
System.out.println("-----------averagingInt------------");
Double collect4 = employees.parallelStream().collect(Collectors.averagingInt(Employee::getAge));
System.out.println("平均年龄:"+collect4);
System.out.println("---------summarizingInt----------------------");
IntSummaryStatistics collect5 = employees.parallelStream().collect(Collectors.summarizingInt(Employee::getAge));
System.out.println("数据统计值:"+collect5);//IntSummaryStatistics{count=8, sum=196, min=20, average=24.500000, max=29}
}
Optional类
- 为了解决空指针,引入了Optional类
- Optional<T> 类(java.util.Optional)是一个容器类,它可以保证类型T的值,代表这个值存在,现在Optional可恶意更好的表达这个概念。并且可以避免空指针异常。
- Optional类的Javadoc描述如下:这是个可以为null的容器对象。如果值存在isPresent()方法会返回true,调用get()方法会返回该对象。
- Optional提供了很多有用的方法,这样我们就不用显示进行空值检测。
- 创建Optional类对象的方法
1. Optional.of(T t):创建一个Options实例,t必须非空
2. Optional.empty():创建一个空的Option实例
3. Optional.ofNullable(T t):t可以为null
- 判断Optional容器是否包含对象
1. boolean isPresent():判断是否包含对象
2. void ifPresent(Consumer<? super T> consumer): 如果有值就执行Consumer接口的实现代码,并且该值会作为参数传递给它。
- 获取Optional容器的对象
1. T get():如果调用对象包含值,返回该值,否则抛出异常
2. T orElse(T other):如果有值则将其返回,否则返回指定的other对象
3. T orElseGet(Supplier<? extends T> other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象
4. T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。