在汇编期间执行非副作用代码可以吗?
Is it fine to execute non side-effect code during assembly time?
当我看到这样的函数时,我有点偏执
@Override
public Mono<List<UserbaseEntityResponse.GroupPrincipal>> merge(UserbaseValidatorResult userbaseValidatorResult,
UserbaseEntityResponse userbaseEntityResponse1,
UserbaseEntityResponse userbaseEntityResponse2) {
List<UserbaseEntityResponse.GroupPrincipal> conflictGroupPrincipal = new ArrayList<>();
userbaseValidatorResult.getResult().getConflicts().forEach(conflicts -> conflicts.forEach(conflict -> {
UserbaseEntityResponse.GroupPrincipal gp1 = findGroupPrincipalFromGroupName(userbaseEntityResponse1, conflict.getGroupName());
UserbaseEntityResponse.GroupPrincipal gp2 = findGroupPrincipalFromGroupName(userbaseEntityResponse2, conflict.getGroupName());
if (userbaseEntityResponse1.getUserbaseId().equals(conflict.getUserbaseId())) {
conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp1)
.withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
} else if (userbaseEntityResponse2.getUserbaseId().equals(conflict.getUserbaseId())) {
conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp2)
.withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
}
}));
return Mono.just(conflictGroupPrincipal);
}
return 语句上面的所有代码都没有包装在 Mono 中,我认为所有语句都在汇编时执行。既然这些操作都没有副作用,可以吗?
一个更大的问题是我们什么时候应该像下面这样将方法包装在 defer 中
public Mono<List<>> merge(args...) {
return Mono.defer(() -> doMerge(args...));
}
public List<> doMerge(args...) {
// business logic
}
我的理解是,每当我们进行 n/w 操作时,我们都应该推迟执行。我的理解对吗?
您提供的示例就是我喜欢称之为“Imposter Reactive Method”的东西。它实际上只是 return 一个响应式发布者的同步方法。
Imposter 响应式方法有一些缺点:
- “工作”正在汇编时执行,这违反了反应流的“nothing happens until you subscribe”设计
- 无法通过
.subscribeOn
在 returned Mono
上将“工作”推迟到另一个线程。因此,如果该方法中执行的任何功能是阻塞的,它可能会阻塞事件循环。
.timeout
、.repeat
和 .retry
等“弹性”运算符在 returned Mono
上不起作用。
至少,您可以像这样使用 Mono.fromCallable
:
return Mono.fromCallable(() -> {
// ... snip ... construct conflictGroupPrincipal...
return conflictGroupPrincipal;
});
您也可以像您提到的那样使用 Mono.defer
,但在这种情况下这太过分了,因为实现是同步的。
(P.S。您可能还会发现 this presentation 有用,我在其中更详细地介绍了 Imposter 反应性方法。)
当我看到这样的函数时,我有点偏执
@Override
public Mono<List<UserbaseEntityResponse.GroupPrincipal>> merge(UserbaseValidatorResult userbaseValidatorResult,
UserbaseEntityResponse userbaseEntityResponse1,
UserbaseEntityResponse userbaseEntityResponse2) {
List<UserbaseEntityResponse.GroupPrincipal> conflictGroupPrincipal = new ArrayList<>();
userbaseValidatorResult.getResult().getConflicts().forEach(conflicts -> conflicts.forEach(conflict -> {
UserbaseEntityResponse.GroupPrincipal gp1 = findGroupPrincipalFromGroupName(userbaseEntityResponse1, conflict.getGroupName());
UserbaseEntityResponse.GroupPrincipal gp2 = findGroupPrincipalFromGroupName(userbaseEntityResponse2, conflict.getGroupName());
if (userbaseEntityResponse1.getUserbaseId().equals(conflict.getUserbaseId())) {
conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp1)
.withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
} else if (userbaseEntityResponse2.getUserbaseId().equals(conflict.getUserbaseId())) {
conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp2)
.withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
}
}));
return Mono.just(conflictGroupPrincipal);
}
return 语句上面的所有代码都没有包装在 Mono 中,我认为所有语句都在汇编时执行。既然这些操作都没有副作用,可以吗?
一个更大的问题是我们什么时候应该像下面这样将方法包装在 defer 中
public Mono<List<>> merge(args...) {
return Mono.defer(() -> doMerge(args...));
}
public List<> doMerge(args...) {
// business logic
}
我的理解是,每当我们进行 n/w 操作时,我们都应该推迟执行。我的理解对吗?
您提供的示例就是我喜欢称之为“Imposter Reactive Method”的东西。它实际上只是 return 一个响应式发布者的同步方法。
Imposter 响应式方法有一些缺点:
- “工作”正在汇编时执行,这违反了反应流的“nothing happens until you subscribe”设计
- 无法通过
.subscribeOn
在 returnedMono
上将“工作”推迟到另一个线程。因此,如果该方法中执行的任何功能是阻塞的,它可能会阻塞事件循环。 .timeout
、.repeat
和.retry
等“弹性”运算符在 returnedMono
上不起作用。
至少,您可以像这样使用 Mono.fromCallable
:
return Mono.fromCallable(() -> {
// ... snip ... construct conflictGroupPrincipal...
return conflictGroupPrincipal;
});
您也可以像您提到的那样使用 Mono.defer
,但在这种情况下这太过分了,因为实现是同步的。
(P.S。您可能还会发现 this presentation 有用,我在其中更详细地介绍了 Imposter 反应性方法。)