在一个管道中链接两个可为空的 Optional
Chaining two nullable Optional in one pipeline
我有 2 个实体 EntityOne
和 EntityTwo
映射到数据库中的 2 个 table。
EntityTwo
中的所有列也出现在 EntityOne
中,因为 EntityTwo
是一个子系统的读取 table。
现在,下面是一些代码来解释一个场景,
我正在使用 spring 数据回购和 java 可选,java-8
void doMagic(EntityOne entitytOne){
//Only if EntityOne present in Database, go delete entity Two.
repoOne
.findById(entitytOne.getPrimaryKey()); //returns Optional<EntityOne>
.ifPresent(this::deleteAssociatedEntityTwo);
}
void deleteAssociatedEntityTwo(EntityOne entityOne){
// Only If able to find an EntityTwo associated with EntityOne in Database, then delete it
fetchEntityTwo(entityOne) //returns Optional<EntityTwo>
.ifPresent(repoTwo::delete);
}
Absent EntityOne::createEntityTwoPrimaryKey
是 EntityOne
class 中的一个方法,它创建一个新的 EntityTwoPrimaryKey 对象并填充所有值。
private Optional<EntityTwo> fetchEntityTwo(EntityOne entityOne) {
// Only if passed entityOne is not null, query the Db and return Optional<EntityTwo>
return Optional
.ofNullable(entityOne)
.map(EntityOne::createEntityTwoPrimaryKey)
.map(repoTwo::findById) //returns Optional<EntityTwo>
.orElse(Optional.empty());
}
现在,如果您看到以上所有 3 种方法都有可选检查,以确保只有在我们拥有所有数据时才会执行操作。
我想在一个可选管道中编写所有代码。
如果我像下面这样写,就没有编译错误。但是当 repoOne.findById
在数据库中找不到任何数据时会发生什么?
我只在 repoTwo::findById
之后检查 ifPresent()
repoOne.findById(entityOne.getEntityOnePrimaryKey())
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById) //returns Optional<EntityTwo>
.ifPresent(repoTwo::delete);
让我们首先验证生成的链是否正确,第一步是将方法分解为 Optional
方法调用的单个链。
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.ifPresent(eOne -> Optional
.ofNullable(eOne)
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete));
}
现在我们可以将 entity -> Optional.ofNullable(entity)
和折叠的 ifPresent
折叠成扁平结构:
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete);
}
到目前为止一切顺利,但是,还有一件事。但是有一个危险的事情,注意这一行:
.map(entityOne::createEntityTwoPrimaryKey)
怎么了?此方法引用不调用 lambda 表达式捕获的实例的 createEntityTwoPrimaryKey
方法,而是调用传递给方法本身的方法!它相当于:
.map(e -> entityOne.createEntityTwoPrimaryKey(e))
不是正确的,因为 NPE 容易出错,因为 entityOne
可以是 null
。您要使用:
// both are equivalent
.map(e -> e.createEntityTwoPrimaryKey(e))
.map(EntityOne::createEntityTwoPrimaryKey)
所以最终链看起来像:
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.map(EntityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete);
}
现在转换确实正确了,那我们回到问题:
If I write like below, There are no compilation errors. But what will happen when repoOne.findById
can't find any data in the database? I'm only checking ifPresent()
after repoTwo::findById
.
考虑以下场景:
repoOne.findById
returns Optional.empty()
- 没有后续的 map
和 flatMap
被调用,因此没有创建任何东西。也没有调用 ifPresent
,因此没有删除任何内容。
repoOne.findById
returns 是一个非空的 Optional
但 map
是 - 同样,从 flatMap
到最后的所有内容都是未调用,因此不会创建或删除任何内容。
一切都在进行 flatMap
return 是一个非空的 Optional
,但是 flatMap
是 - 这里的事情开始变得有趣,因为 createEntityTwoPrimaryKey
是它所做的一切,但 ifPresent
中的删除不是。但是,我假设如果创建了某些东西,它也很可能会被发现,所以这种情况确实是一种边缘情况。
最终结果取决于delete
方法调用,但是,它是void
return类型。只要不抛出RuntimeException
就是安全的
总结,我发现 Optional
链是安全的。您可能希望使用 @Transactional
注释该方法以回滚可能的 RuntimeException
.
我有 2 个实体 EntityOne
和 EntityTwo
映射到数据库中的 2 个 table。
EntityTwo
中的所有列也出现在 EntityOne
中,因为 EntityTwo
是一个子系统的读取 table。
现在,下面是一些代码来解释一个场景, 我正在使用 spring 数据回购和 java 可选,java-8
void doMagic(EntityOne entitytOne){
//Only if EntityOne present in Database, go delete entity Two.
repoOne
.findById(entitytOne.getPrimaryKey()); //returns Optional<EntityOne>
.ifPresent(this::deleteAssociatedEntityTwo);
}
void deleteAssociatedEntityTwo(EntityOne entityOne){
// Only If able to find an EntityTwo associated with EntityOne in Database, then delete it
fetchEntityTwo(entityOne) //returns Optional<EntityTwo>
.ifPresent(repoTwo::delete);
}
Absent EntityOne::createEntityTwoPrimaryKey
是 EntityOne
class 中的一个方法,它创建一个新的 EntityTwoPrimaryKey 对象并填充所有值。
private Optional<EntityTwo> fetchEntityTwo(EntityOne entityOne) {
// Only if passed entityOne is not null, query the Db and return Optional<EntityTwo>
return Optional
.ofNullable(entityOne)
.map(EntityOne::createEntityTwoPrimaryKey)
.map(repoTwo::findById) //returns Optional<EntityTwo>
.orElse(Optional.empty());
}
现在,如果您看到以上所有 3 种方法都有可选检查,以确保只有在我们拥有所有数据时才会执行操作。 我想在一个可选管道中编写所有代码。
如果我像下面这样写,就没有编译错误。但是当 repoOne.findById
在数据库中找不到任何数据时会发生什么?
我只在 repoTwo::findById
ifPresent()
repoOne.findById(entityOne.getEntityOnePrimaryKey())
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById) //returns Optional<EntityTwo>
.ifPresent(repoTwo::delete);
让我们首先验证生成的链是否正确,第一步是将方法分解为 Optional
方法调用的单个链。
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.ifPresent(eOne -> Optional
.ofNullable(eOne)
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete));
}
现在我们可以将 entity -> Optional.ofNullable(entity)
和折叠的 ifPresent
折叠成扁平结构:
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.map(entityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete);
}
到目前为止一切顺利,但是,还有一件事。但是有一个危险的事情,注意这一行:
.map(entityOne::createEntityTwoPrimaryKey)
怎么了?此方法引用不调用 lambda 表达式捕获的实例的 createEntityTwoPrimaryKey
方法,而是调用传递给方法本身的方法!它相当于:
.map(e -> entityOne.createEntityTwoPrimaryKey(e))
不是正确的,因为 NPE 容易出错,因为 entityOne
可以是 null
。您要使用:
// both are equivalent
.map(e -> e.createEntityTwoPrimaryKey(e))
.map(EntityOne::createEntityTwoPrimaryKey)
所以最终链看起来像:
void doMagic(EntityOne entityOne) {
repoOne.findById(entityOne.getPrimaryKey())
.map(EntityOne::createEntityTwoPrimaryKey)
.flatMap(repoTwo::findById)
.ifPresent(repoTwo::delete);
}
现在转换确实正确了,那我们回到问题:
If I write like below, There are no compilation errors. But what will happen when
repoOne.findById
can't find any data in the database? I'm only checkingifPresent()
afterrepoTwo::findById
.
考虑以下场景:
repoOne.findById
returnsOptional.empty()
- 没有后续的map
和flatMap
被调用,因此没有创建任何东西。也没有调用ifPresent
,因此没有删除任何内容。repoOne.findById
returns 是一个非空的Optional
但map
是 - 同样,从flatMap
到最后的所有内容都是未调用,因此不会创建或删除任何内容。一切都在进行
flatMap
return 是一个非空的Optional
,但是flatMap
是 - 这里的事情开始变得有趣,因为createEntityTwoPrimaryKey
是它所做的一切,但ifPresent
中的删除不是。但是,我假设如果创建了某些东西,它也很可能会被发现,所以这种情况确实是一种边缘情况。最终结果取决于
delete
方法调用,但是,它是void
return类型。只要不抛出RuntimeException
就是安全的
总结,我发现 Optional
链是安全的。您可能希望使用 @Transactional
注释该方法以回滚可能的 RuntimeException
.