OPTIONAL的一些用法

OPTIONAL是JAVA8带来的一个类,不知道大家是否和我一样,在一开始接触的时候,会毕竟犹豫,什么时候使用OPTIONAL,什么时候又不应该使用呢?以下是我在实际使用了一段时间之后的感受。

什么时候用OPTIONAL作为返回值?

我们大概都知道,Optional类型的对象(例如:op),我们可以使用optional.isPresent()来表达optional内实际有没有东西。如果有,我们就可以调用optional.get()方法获取其中的内容,以此来完成我们的业务逻辑。正因如此:Optional对象可以被理解为一个,可能持有东西,也可能没有的一个对象。
所以,当我们把Optional做成方法的返回值的时候,我们就可以把这个方法解读为,这个方法可能会返回对象,也可能不会。例如:

// 因为'ANDY'这个人,不一定就能查询到,所以我们返回的是一个Optional对象
Optional<User> userOptional = findOneUserByUsername("ANDY");
if (userOptional.isPresent()) {
	User user = userOptional.get();
	System.out.println(user.getAge());
	// 更多业务逻辑
}

当这个实践结合到他的反面,也就是,当一个方法,必定会返回一个对象的时候(不可能返回NULL)的时候。我们就可以按照这个约定简化代码的书写:

// 哪怕没有人,也至少可以返回一个0吧
UserCount userCount = getLatestUserCount();
//因为方法没有返回Optional,我们在这里可以不检查NULL, 直接使用其返回结果
System.out.println(userCount.getCount());
// 更多业务逻辑

我们平时在写代码的时候,有没有这样的困惑。每一个方法的返回值,我都需要检查NULL或者空的情况吗?我的原则是这样的:

  1. 对于第三方的,或者不受控的部门写的代码,最好还是都要检查,确保代码的健壮性。哪怕出错了,也能给出一个有意义的错误提醒,并且记录日志;
  2. 对于内部的API,我会采用以上的Optional的约定,并且在CodeReview和一些引导中宣贯,这会使得写代码的日子好过很多。

最后,既然方法返回值可以这样去使用,那么,传入参数是否也可以这样来操作呢?我的答案是:YES

其他常用手法

当我们手持一个Optional对象,需要获取其中的值的时候,我们除了使用optional.isPresent(),我们还能使用什么方式去获取他?其实,Optional有很多方法,可以使我们原本需要多行代码才能完成的逻辑,没有if,甚至是一行代码就可以完成。

orElse

Optional<User> userOptional = findOneUserByUsername("ANDY");
// 如果人不存在,就返回-1,代表不合法的年龄
Integer age = userOptional.map(value -> value.getAge()).orElse(-1);

关于orElse还有几个变形:

orElseGet

常常用在,我们要从数据库获取一个对象,并做更新。如果数据库里没有,我们就创建出来一个,并更新的场景

User user = findOneUserByUsername("ANDY").orElseGet(() -> {
	User newUser = new User();
	newUser.setUsername("ANDY");
	return newUser;
});

user.setAge(18);
userRepository.save(user);
orElseThrow

常常用在,我们要从数据库获取一个对象,如果数据库里没有,我们就直接报错

User user = findOneUserByUsername("ANDY")
				.orElseThrow(() -> new ApiErrorException(RESOURCE_NOT_FOUND, "用户", "ANDY"));
user.setAge(18);
userRepository.save(user);

Optional.ofNullable

这是一个很有意思的方法,面对大量的第三方依赖,如果我们也想使用以上的代码风格。可以直接使用这个方法生成一个Optional对象,哪怕其持有的对象是NULL,也没问题。这里,我经常会用这个方法,来减少无谓的if判断。例如:

// 我们以前会这么写?
Integer plus(Interge a, Interge b) {
	if (Objects.isNull(a) && Objects.isNull(b)) {
		return Integer.valueOf(0);
	}

	if (Objects.isNull(a)) {
		return b;
	}
	
	if (Objects.isNull(b)) {
		return a;
	}

	return a + b;
}

// 我们现在可以这么写,生活多美好
Integer plus(Interge a, Interge b) {
	return Optional.ofNullable(a).orElse(0) + Optional.ofNullable(b).orElse(0);
}

// 你也许会说,我可以这么写。但如果orElse换成orElseThrow呢?Optional会更加灵活
Integer plus(Interge a, Interge b) {
	return (Objects.isNull(a)? 0 : a) + (Objects.isNull(b)? 0 : b);
}

对了,这个方法有一个兄弟,是Optional.of,小心,如果传如为空的对象,会直接报错。目前我几乎没有怎么使用过它。

可以跟stream背后的一些通用方法

当组合使用Else和filter / map的时候,还是可以起到减少代码量,并且提高可读性的作用:

如果要获取一个没有被删除的用户


// 以前
User user = findOneUserByUsername("ANDY");
if (Objects.isNull(user) || user.getStatus() == "DELETED") {
	throw new ApiErrorException(RESOURCE_NOT_FOUND, "用户", "ANDY");
}
Integer age = user.getAge()
// 更多业务逻辑


// 现在
Integer age = findOneUserByUsername("ANDY")
	.filter(user -> user.getStatus() != "DELETED")
	.map(User::getAge)
	.orElseThrow(() -> new ApiErrorException(RESOURCE_NOT_FOUND, "用户", "ANDY"));

// 更多业务逻辑

那么,大家还有什么神奇的骚操作呢?

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值