在汇编期间执行非副作用代码可以吗?

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 响应式方法有一些缺点:

  1. “工作”正在汇编时执行,这违反了反应流的“nothing happens until you subscribe”设计
  2. 无法通过 .subscribeOn 在 returned Mono 上将“工作”推迟到另一个线程。因此,如果该方法中执行的任何功能是阻塞的,它可能会阻塞事件循环。
  3. .timeout.repeat.retry 等“弹性”运算符在 returned Mono 上不起作用。

至少,您可以像这样使用 Mono.fromCallable

return Mono.fromCallable(() -> {

    // ... snip ... construct conflictGroupPrincipal...

    return conflictGroupPrincipal;
});

您也可以像您提到的那样使用 Mono.defer,但在这种情况下这太过分了,因为实现是同步的。

(P.S。您可能还会发现 this presentation 有用,我在其中更详细地介绍了 Imposter 反应性方法。)