前文
Optional 对很多人来说还是比较陌生的一个东西,但在stream流里面其实已经出现过很多次了
stream流里的Optional实例可以看一下笔者上一篇文:工作中都爱用的Stream流,多实例详解过滤、匹配、归并等超完整笔记~(由浅入深的函数式编程②)
概述
使用Optional主要是为了避免空指针异常
使用Optional
创建对象
一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象。
User user = getUser();
Optional<User> userOptional = Optional.ofNullable(user);
//即使getUser()方法返回的是null,也不会报空指针异常
userOptional.ifPresent(user -> System.out.println(user.getName()));
但其实更简便且持久生效的便是将getUser()方法的返回对象改为Optional:
public static Optional<User> getUser(){
User user = new User();
xxxx//直接加user对象内容
return Optional.ofNullable(user);
}
note:从数据库取内容则dao方法改为返回Optional对象。
修改后则直接:
Optional<User> userOptional = getUser();
userOptional.ifPresent(user -> System.out.println(user.getName()));
安全消费值
获取到Optional对象后需要消费数据,可以使用 ifPresent() 方法,此方法会先行判断封装数据是否为空,不为空时才会继续执行具体的消费代码。
这样消费就更安全。
(上述实例已经使用过了)
安全获取值
可以直接get(),但是并不安全,如果为空则会返回空指针。
orElseGet
先判空,不为空则能获取,如果为空则根据传入的参数来创建对象作为默认值返回。
Optional<User> userOptional = getUser();
User user = userOptional.orElseGet(() -> new User);
System.out.println(user.getName());
orElseThrow
先判空,不为空则能获取,如果为空则根据传入参数创建异常抛出。
Optional<User> userOptional = Optional.ofNullable(getUser());
try{
User user = userOptional.orElseThrow(Supplier<Throwable> () -> new RuntimeException("user为空"));
System.out.println(user.getName());
}catch (Throwable throwable){
throwable.printStackTrace();
}
过滤
当符合条件时,则会返回需求数据;不符合条件则会被过滤掉,返回一个新的Optional对象,此对象为null.
Optional<User> userOptional = getUserOptional();
Optional<User> optional = userOptional.filter(user -> user.getAge() > 18)
.ifPresent(user -> System.out.println(user.getName()));
判断
布尔类型的isPresent()
Optional<User> userOptional = getUserOptional();
if(userOptional.isPresent()){
//已经判空后则可以使用get()
System.out.println(userOptional.get().getName());
}
数据转换
和stream流的map很类似,可以转换数据为Optional对象。
如果进入空置也不会报空指针。
Optional<User> userOptional = getUserOptional();
userOptional.map(user -> user.getEquipments())
.ifPresent(equipments -> System.out.println(equipments));
==================================================
Optional的基本和常用的知识如上所示。
接下来是关于函数式接口的内容。
函数式接口
概述
函数接口:只有一个抽象方法的接口。
stream流一直在使用函数接口。
JDK的函数式接口一般会加一个注解:@FunctionalInterface
常见函数式接口
不需要记住,底层在使用,了解熟练即可。
-
Consumer消费接口
可以在方法中对传入的参数进行消费。 -
Function计算转换接口
根据接口里的抽象方法的参数列表和返回值类型,在方法里对传入的参数进行计算或转换,然后返回结果。 -
Predicate判断接口
根据接口里的抽象方法的参数列表和返回值类型,在方法里判断参数条件,返回判断结果。 -
Supplier生产型接口
根据接口里的抽象方法的参数列表和返回值类型,在方法里创建对象,返回创建对象。
常用默认方法
- and/or
可以拼接条件等
stream流里用Lambda表达式时注意将and改为&&,or改为||
实例:
//打印年龄和姓名长度同时符合条件的用户
List<User> users = getUsers();
users.stream()
.filter(user -> user.getAge()>17 && user.getName().length()>1)
.forEach(user -> System.out.println(user.getAge()+"+"+user.getName()));
- negate
相当于在判断前加" !",取反。
实例:
//筛选姓名长度不大于2的用户
List<User> users = getUsers();
users.stream()
.filter(user -> user.getName().length()>2)
.negate()
方法引用
概述
进一步简化Lambda的方式。
使用场景
方法体只有一个引用方法的情况
实例:
List<User> users = getUsers();
users.stream()
//一个方法的情况
.map(user->user.getAge())
//就可以改成方法引用
.map(user::getAge)
基本格式
由上实例可总结:
类名/对象名::方法名
构造器引用
概述
方法体内的一行代码是构造器则可以使用构造器引用
格式
类名::new
以上都可以使用idea直接优化,不需要特意记住。
===================================================================
关于函数式编程就暂时更新到这里啦,工作中实际使用和看懂代码基本已经没有大问题了。码字不易,希望大家多多支持小soul呀!😃