这篇文章主要讲解了“如何使用Java Optional类”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用Java Optional类”吧!
成都创新互联公司从2013年开始,是专业互联网技术服务公司,拥有项目成都网站建设、网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元青铜峡做网站,已为上家服务,为青铜峡各地企业和个人服务,联系电话:13518219792注意:示例代码要求使用Java 11及更高版本。所有代码在 Vavr0.10.2环境下完成测试。
Java Optional 简介
Optional 并不是什么新概念,像 Haskell、Scala 这样的函数式编程语言已经提供了实现。调用方法后,返回值未知或者不存在(比如 null)的情况下,用 Optional 处理非常好用。下面通过实例进行介绍。
新建 Optional 实例
首先,需要获得 Optional 实例,有以下几种方法可以新建 Optional 实例。不仅如此,还可以创建empty Optional。方法一,通过 value 创建,过程非常简单:
Optional four = Optional.of(Integer.valueOf(4));
if (four.isPresent){
System.out.println("Hoorayy! We have a value");
}
else {
System.out.println("No value");
}
为Integer 4 新建一个Optional实例。这种方法得到的 Optional 始终包含一个 value 且不为 null,例如上面这个示例。使用 ifPresent() 可以检查value是否存在。可以注意到 four 不是 Integer,而是一个装有整数的容器。如果确认 value 存在,可以用 get() 方法执行拆箱操作。具有讽刺意味的是,调用 get() 前如果不进行检查,可能会抛出 NoSuchElementException。
方法二,得到 Optional 对象的另一种方法是使用 stream。Stream提供的一些方法会返回Optional,可以用来检查结果是否存在,例如:
findAny
findFirst
max
min
reduce
查看下面的代码段:
Optionalcar = cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst();
方法三,使用 Nullable 新建 Optional。可能产生 null:
Optionalnullable = Optional.ofNullable(client.getRequestData());
最后,可以新建一个 empty Optional:
Optionalnothing = Optional.empty();
如何使用 Optional
获得 Optional 对象后即可使用。一种典型的场景是在 Spring 仓库中根据 Id 查找记录。可以使用 Optional 实现代码逻辑,避免 null 检查(顺便提一下,Spring 也支持 Vavr Option)。比如,从图书仓库里查找一本书。
Optionalbook = repository.findOne("some id");
首先,如果有这本书,可以继续执行对应的业务逻辑。在前面的章节用 if-else实现了功能。当然,还有其他办法:Optional 提供了一个方法,接收 Consumer 对象作为输入:
repository.findOne("some id").ifPresent(book -> System.out.println(book));
还可以直接使用方法引用,看起来更简单:
repository.findOne("some id").ifPresent(System.out::println);
如果仓库中没有该书,可以用ifPresentOrElseGet提供回调函数:
repository.findOne("some id").ifPresentOrElseGet(book->{
// 如果 value 存在
}, ()->{
// 如果 value 不存在
});
如果结果不存在,可以返回另一个value:
Book result = repository.findOne("some id").orElse(defaultBook);
但是,Optional 也有缺点,使用时需要注意。最后一个例子中,“确保”无论如何都能获得一本书,可能在仓库中,也可能来自 orElse。但如果默认的返回值不是常量或者需要支持一些复杂方法该怎么办?首先,Java 无论如何都会执行 findOne,然后调用 orElse方法。默认返回值可以为常量,但正如我之前所说那样,执行过程比较耗时。
另一个示例
下面用一个简单的示例介绍如何实际使用 Optional 和 Option 类。有一个 CarRepository,可以根据提供的 ID(比如车牌号)查找汽车,接下来用这个示例介绍如何使用 Optional 和 Option。
首先,加入下面代码
从 POJO 类 Car 开始。它遵循 immutable 模式,所有字段都标记为 final,只包含 getter 没有 setter。初始化时提供所有数据:
public class Car {
private final String name;
private final String id;
private final String color;
public Car (String name, String id, String color){
this.name = name;
this.id = id;
this.color = color;
}
public String
getId(){
return id;
}
public String
getColor() {
return color;
}
public String
getName() {
return name;
}
@Override
public String
toString() {
return "Car "+name+" with license id "+id+" and of color "+color;
}
}
接下来创建 CarRepository类。提供两种方法根据Id查找汽车:一种是老办法,使用 Optional。和之前在 Spring 仓库的做法类似,结果可能为 null。
publicclass CarRepository {
private List cars;
public CarRepository(){
getSomeCars();
}
Car
findCarById(String id){
for (Car car: cars){function(){ //外汇跟单www.gendan5.com if (car.getId().equalsIgnoreCase(id)){
return car;
}
}
return null;
}
Optional findCarByIdWithOptional(String id){
return cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst();
}
private void getSomeCars(){
cars = new ArrayList<>();
cars.add(new Car("tesla", "1A9 4321", "red"));
cars.add(new Car("volkswagen", "2B1 1292", "blue"));
cars.add(new Car("skoda", "5C9 9984", "green"));
cars.add(new Car("audi", "8E4 4321", "silver"));
cars.add(new Car("mercedes", "3B4 5555", "black"));
cars.add(new Car("seat", "6U5 3123", "white"));
}
}
注意:初始化过程会在仓库中添加一些汽车模拟数据,便于演示。为了突出重点,避免问题复杂化,下面的讨论专注于 Optional 和 Option。
使用Java Optional
使用JUnit创建一个新测试:
@Test
void getCarById(){
Car car = repository.findCarById("1A9 4321");
Assertions.assertNotNull(car);
Car nullCar = repository.findCarById("M 432 KT");
Assertions.assertThrows(NullPointerException.class, ()->{
if (nullCar == null){
throw new NullPointerException();
}
});
}
上面的代码段采用了之前的老办法。查找捷克牌照1A9 4321对应的汽车,检查该车是否存在。输入俄罗斯车牌找不到对应的汽车,因为仓库中只有捷克车。结果为 null 可能会抛出 NullPointerException。
接下来用Java Optional。第一步,获得 Optional 实例,从存储库中使用指定方法返回 Optional:
@Test
void getCarByIdWithOptional(){
Optional tesla = repository.findCarByIdWithOptional("1A9 4321");
tesla.ifPresent(System.out::println);
}
这时调用findCarByIdWithOptional方法打印车辆信息(如果有的话)。运行程序,得到以下结果:
Car tesla with license id 1A9 4321 and of color red
但是,如果代码中没有特定方法该怎么办?这种情况可以从方法返回可能包含 null 的 Optional,称为nullable。
Optional nothing = Optional.ofNullable(repository.findCarById("5T1 0965"));
Assertions.assertThrows(NoSuchElementException.class, ()->{
Car car = nothing.orElseThrow(()->new NoSuchElementException());
});
上面这段代码段中,我们发现了另一种方法。通过 findCarById 创建 Optional,如果未找到汽车可以返回 null。没有找到车牌号5T1 0965汽车时,可以用 orElseThrow 手动抛出 NoSuchElementException。另一种情况,如果请求的数据不在仓库中,可以用orElse返回默认值:
Car audi = repository.findCarByIdWithOptional("8E4 4311")
.orElse(new Car("audi",
"1W3 4212",
"yellow"));
if (audi.getColor().equalsIgnoreCase("silver")){
System.out.println("We have silver audi in garage!");
}
else {
System.out.println("Sorry, there is no silver audi, but we called you a taxi");
}
好的,车库里没有找到银色奥迪,只好打车了!
使用 Vavr Option
Vavr OptionOption提供了另一种解决办法。首先,在项目中添加依赖,(使用 Maven)安装 Vavr:
io.vavr
vavr
0.10.2
简而言之,Vavr 提供了类似的 API 新建 Option 实例。可以从 nullable 新建 Option 实例,像下面这样:
Optionnothing = Option.of(repository.findCarById("T 543 KK"));
也可以用 none 静态方法创建一个empty容器:
Optionnullable = Option.none();
此外,还有一种方法可以用 Java Optional 新建 Option。看下面这段代码:
Optionresult = Option.ofOptional(repository.findCarByIdWithOptional("5C9 9984"));
使用 Vavr Option,可以使用与 Optional相同的 API 来完成上述任务。例如,设置默认值:
Option result = Option.ofOptional(repository.findCarByIdWithOptional("5C9 9984"));
Car skoda = result.getOrElse(new Car("skoda",
"5E2 4232",
"pink"));
System.out.println(skoda);
或者,请求的数据不存在时可以抛出异常:
Option nullable = Option.none();
Assertions.assertThrows(NoSuchElementException.class, ()->{
nullable.getOrElseThrow(()->new NoSuchElementException());
});
另外,当数据不可用时,可以执行以下操作:
nullable.onEmpty(()->{
///runnable
});
如何根据数据是否存在来执行相应操作,类似 Optional 中 ifPresent?有几种实现方式。与 Optional 中 isPresent 类似,在 Option 中对应的方法称为 isDefined:
if (result.isDefined()){
// 实现功能
}
然而,使用 Option能摆脱 if-else。是否可以用Optional相同的方式完成?使用 peek 操作:
result.peek(val -> System.out.println(val)).onEmpty(() -> System.out.println("Result is missed"));
此外,Vavr Option还提供了一些其他非常有用的方法,在函数式编程上比Optional类效果更好。因此,建议您花一些时间来探索 Vavr Option javadocs尝试使用这些API。我会持续跟进一些类似 map、narrow、isLazy 和 when 这样有趣的功能。
感谢各位的阅读,以上就是“如何使用Java Optional类”的内容了,经过本文的学习后,相信大家对如何使用Java Optional类这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!