Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Java8选项,在三个选项都存在的情况下执行操作?_Java_Java 8_Optional - Fatal编程技术网

如何使用Java8选项,在三个选项都存在的情况下执行操作?

如何使用Java8选项,在三个选项都存在的情况下执行操作?,java,java-8,optional,Java,Java 8,Optional,我有一些使用Java选项的(简化)代码: Optional<User> maybeTarget = userRepository.findById(id1); Optional<String> maybeSourceName = userRepository.findById(id2).map(User::getName); Optional<String> maybeEventName = eventRepository.findById(id3).map(

我有一些使用Java选项的(简化)代码:

Optional<User> maybeTarget = userRepository.findById(id1);
Optional<String> maybeSourceName = userRepository.findById(id2).map(User::getName);
Optional<String> maybeEventName = eventRepository.findById(id3).map(Event::getName);

maybeTarget.ifPresent(target -> {
    maybeSourceName.ifPresent(sourceName -> {
        maybeEventName.ifPresent(eventName -> {
            sendInvite(target.getEmail(), String.format("Hi %s, $s has invited you to $s", target.getName(), sourceName, meetingName));
        }
    }
}
可选的maybeTarget=userRepository.findById(id1);
可选的maybeSourceName=userRepository.findById(id2.map)(User::getName);
可选的maybeEventName=eventRepository.findById(id3.map)(Event::getName);
可能目标。如果存在(目标->{
可能是源名称。如果存在(sourceName->{
maybeEventName.ifPresent(事件名称->{
sendInvite(target.getEmail(),String.format(“您好%s,$s已邀请您访问$s”,target.getName(),sourceName,meetingName));
}
}
}
不用说,这看起来和感觉都很糟糕。但我想不出其他方法来以嵌套更少、可读性更高的方式来实现这一点。我考虑过将3个选项流式处理,但放弃了使用
。过滤器(可选::isPresent)
的想法,然后使用
。映射(可选::get)
感觉更糟


那么,有没有更好的、更“Java 8”或“可选读写”的方法来处理这种情况(基本上是多个选项都需要计算一个最终操作)?

类似的方法如何

 if(Stream.of(maybeTarget, maybeSourceName,  
                        maybeEventName).allMatch(Optional::isPresent))
  {
   sendinvite(....)// do get on all optionals.
  }

话虽如此。如果您在数据库中查找的逻辑只是发送邮件,那么如果
maybeTarget.ifPresent()
为false,那么获取其他两个值就没有意义了,不是吗?恐怕这种逻辑只能通过传统的If-else语句来实现。

第一种方法并不完美(它不支持惰性-仍将触发所有3个数据库调用):

Optional target=userRepository.findById(id1);
可选的sourceName=userRepository.findById(id2.map)(User::getName);
可选的eventName=eventRepository.findById(id3.map)(Event::getName);
if(Stream.of(target,sourceName,eventName).anyMatch(obj->!obj.isPresent())){
返回;
}
sendInvite(target.get()、sourceName.get()、eventName.get());
下面的示例有点冗长,但它支持惰性和可读性:

private void sendIfValid() {
    Optional<User> target = userRepository.findById(id1);
    if (!target.isPresent()) {
        return;
    }
    Optional<String> sourceName = userRepository.findById(id2).map(User::getName);
    if (!sourceName.isPresent()) {
        return;
    }
    Optional<String> eventName = eventRepository.findById(id3).map(Event::getName);
    if (!eventName.isPresent()) {
        return;
    }
    sendInvite(target.get(), sourceName.get(), eventName.get());
}

private void sendInvite(User target, String sourceName, String eventName) {
    // ...
}
private void sendiffalid(){
可选目标=userRepository.findById(id1);
如果(!target.isPresent()){
返回;
}
可选的sourceName=userRepository.findById(id2.map)(User::getName);
如果(!sourceName.isPresent()){
返回;
}
可选的eventName=eventRepository.findById(id3.map)(Event::getName);
如果(!eventName.isPresent()){
返回;
}
sendInvite(target.get()、sourceName.get()、eventName.get());
}
私有void sendInvite(用户目标、字符串sourceName、字符串eventName){
// ...
}

使用helper函数,事情至少有一点不嵌套:

@FunctionalInterface
interface TriConsumer<T, U, S> {
    void accept(T t, U u, S s);
}

public static <T, U, S> void allOf(Optional<T> o1, Optional<U> o2, Optional<S> o3,
       TriConsumer<T, U, S> consumer) {
    o1.ifPresent(t -> o2.ifPresent(u -> o3.ifPresent(s -> consumer.accept(t, u, s))));
}

明显的缺点是,对于每一个不同数量的
可选的
s

您都需要一个单独的helper函数重载。我认为流式处理三个
可选的
s是一种过分的做法,为什么不简单呢

if (maybeTarget.isPresent() && maybeSourceName.isPresent() && maybeEventName.isPresent()) {
  ...
}

在我看来,这比使用流API更清楚地说明了条件逻辑。

< P>我认为你应该考虑采取另一种方法。

首先,我不会在开始时向DB发出这三个调用。相反,我会发出第一个查询,只有当结果存在时,我才会发出第二个查询。然后,我会对第三个查询应用相同的原理,最后,如果最后一个结果也存在,我会发送invite。这样可以避免在eit时向DB发出不必要的调用她的前两个结果之一不存在

为了使代码更具可读性、可测试性和可维护性,我还将每个DB调用提取到它自己的私有方法中,并用
Optional链接它们。ifPresent

public void sendInvite(Long targetId, Long sourceId, Long meetingId) {
    userRepository.findById(targetId)
        .ifPresent(target -> sendInvite(target, sourceId, meetingId));
}

private void sendInvite(User target, Long sourceId, Long meetingId) {
    userRepository.findById(sourceId)
        .map(User::getName)
        .ifPresent(sourceName -> sendInvite(target, sourceName, meetingId));
}

private void sendInvite(User target, String sourceName, Long meetingId) {
    eventRepository.findById(meetingId)
        .map(Event::getName)
        .ifPresent(meetingName -> sendInvite(target, sourceName, meetingName));
}

private void sendInvite(User target, String sourceName, String meetingName) {
    String contents = String.format(
        "Hi %s, $s has invited you to $s", 
        target.getName(), 
        sourceName, 
        meetingName);
    sendInvite(target.getEmail(), contents);
}

我采用了相同的方法,只在需要时调用DB,这也很冗长,但很懒惰。我还简化了一点。考虑到您有以下3种方法:

public static Optional<String> firstCall() {
    System.out.println("first call");
    return Optional.of("first");
}

public static Optional<String> secondCall() {
    System.out.println("second call");
    return Optional.empty();
}

public static Optional<String> thirdCall() {
    System.out.println("third call");
    return Optional.empty();
}

因为原始代码的副作用正在被执行(发送电子邮件),而不是提取或生成值,嵌套的
ifPresent
调用似乎是合适的。原始代码似乎不太糟糕,实际上它似乎比已经提出的一些答案要好。但是,lambdas语句和
Optional
类型的局部变量似乎确实添加了大量clutter

首先,我将自由地修改原始代码,将其包装在一个方法中,为参数指定好的名称,并生成一些类型名称。我不知道实际代码是否是这样的,但这对任何人来说都不应该感到惊讶

// original version, slightly modified
void inviteById(UserId targetId, UserId sourceId, EventId eventId) {
    Optional<User> maybeTarget = userRepository.findById(targetId);
    Optional<String> maybeSourceName = userRepository.findById(sourceId).map(User::getName);
    Optional<String> maybeEventName = eventRepository.findById(eventId).map(Event::getName);

    maybeTarget.ifPresent(target -> {
        maybeSourceName.ifPresent(sourceName -> {
            maybeEventName.ifPresent(eventName -> {
                sendInvite(target.getEmail(), String.format("Hi %s, %s has invited you to %s",
                                                  target.getName(), sourceName, eventName));
            });
        });
    });
}
现在,让我们来处理一些可选的东西。正如我上面所说的,
ifPresent
是我们的方法,因为我们想做一些有副作用的事情。它还提供了一种“提取”的方法从一个Optional中获取值,并将其绑定到一个名称,但仅在lambda表达式的上下文中。由于我们希望对三个不同的Optional执行此操作,因此需要调用嵌套。嵌套允许外部lambda中的名称被内部lambda捕获。这允许我们将名称绑定到从Optional中提取的值,但前提是这些值存在。这实际上不能用线性链来完成,因为某些中间数据结构(如元组)是构建部分结果所必需的

最后,在最内层的lambda中,我们调用上面定义的helper方法

void inviteById(UserId targetId, UserId sourceID, EventId eventId) {
    userRepository.findById(targetId).ifPresent(
        target -> userRepository.findById(sourceID).ifPresent(
            source -> eventRepository.findById(eventId).ifPresent(
                event -> setupInvite(target, source, event))));
}
请注意,我内联了选项,而不是将它们保存在局部变量中。这更好地揭示了嵌套结构。如果其中一个查找没有找到任何内容,它还提供了操作的“短路”,因为
ifPresent
只是对空的可选内容不执行任何操作

不过,在我看来,它仍然有点密集。我认为原因是,该代码仍然依赖于一些外部存储库来进行查找。将其与可选处理混合在一起有点不舒服。一种可能是简单地将查找提取到它们自己的方法
findUser
findEvent中。这些是
firstCall()
       .flatMap(x -> secondCall().map(y -> Stream.of(x, y))
              .flatMap(z -> thirdCall().map(n -> Stream.concat(z, Stream.of(n)))))
       .ifPresent(st -> System.out.println(st.collect(Collectors.joining("|"))));
// original version, slightly modified
void inviteById(UserId targetId, UserId sourceId, EventId eventId) {
    Optional<User> maybeTarget = userRepository.findById(targetId);
    Optional<String> maybeSourceName = userRepository.findById(sourceId).map(User::getName);
    Optional<String> maybeEventName = eventRepository.findById(eventId).map(Event::getName);

    maybeTarget.ifPresent(target -> {
        maybeSourceName.ifPresent(sourceName -> {
            maybeEventName.ifPresent(eventName -> {
                sendInvite(target.getEmail(), String.format("Hi %s, %s has invited you to %s",
                                                  target.getName(), sourceName, eventName));
            });
        });
    });
}
void setupInvite(User target, User source, Event event) {
    sendInvite(target.getEmail(), String.format("Hi %s, %s has invited you to %s",
               target.getName(), source.getName(), event.getName()));
}
void inviteById(UserId targetId, UserId sourceID, EventId eventId) {
    userRepository.findById(targetId).ifPresent(
        target -> userRepository.findById(sourceID).ifPresent(
            source -> eventRepository.findById(eventId).ifPresent(
                event -> setupInvite(target, source, event))));
}
void inviteById(UserId targetId, UserId sourceID, EventId eventId) {
    findUser(targetId).ifPresent(
        target -> findUser(sourceID).ifPresent(
            source -> findEvent(eventId).ifPresent(
                event -> setupInvite(target, source, event))));
}
/**
 * Returns an optional contained a triple if all arguments are present,
 * otherwise an absent optional
 */
public static <L, M, R> Optional<Triple<L, M, R>> product(Optional<L> left,
        Optional<M> middle, Optional<R> right) {
    return left.flatMap(l -> middle.flatMap(m -> right.map(r -> Triple.of(l, m, r))));
}

// Used as
product(maybeTarget, maybeSourceName, maybeEventName).ifPresent(this::sendInvite);
User target = userRepository.findById(id1).orElse(null);
User source = userRepository.findById(id2).orElse(null);
Event event = eventRepository.findById(id3).orElse(null);

if (target != null && source != null && event != null) {
    String message = String.format("Hi %s, %s has invited you to %s",
        target.getName(), source.getName(), event.getName());
    sendInvite(target.getEmail(), message);
}
return userRepository.findById(id)
                .flatMap(target -> userRepository.findById(id2)
                        .map(User::getName)
                        .flatMap(sourceName -> eventRepository.findById(id3)
                                .map(Event::getName)
                                .map(eventName-> createInvite(target, sourceName, eventName))))
    class OptionalSupplier {

        private final Supplier<Optional<?>> optionalSupplier;
        private Optional<?> evaluatedOptional = null;

        public OptionalSupplier(Supplier<Optional<?>> supplier) {
            this.optionalSupplier = supplier;
        }

        public Optional<?> getEvaluatedOptional() {
            if (evaluatedOptional == null)
                evaluatedOptional = optionalSupplier.get();

            return evaluatedOptional;
        }
    }
    class OptionalSemaphores {

        private List<OptionalSupplier> optionalSuppliers;
        private List<Object> results = null;
        private boolean allPresent;

        public OptionalSemaphores(Supplier<Optional<?>>... suppliers) {
            optionalSuppliers = Stream.of(suppliers)
                    .map(OptionalSupplier::new)
                    .collect(Collectors.toList());

            allPresent = optionalSuppliers.stream()
                    .map(OptionalSupplier::getEvaluatedOptional)
                    .allMatch(Optional::isPresent);

            if (allPresent)
                results = optionalSuppliers.stream()
                        .map(OptionalSupplier::getEvaluatedOptional)
                        .map(Optional::get)
                        .collect(Collectors.toList());
        }

        public boolean isAllPresent() {
            return allPresent;
        }

        public <T> T execute(Function<List<Object>, T> function, T defaultValue) {
            return (allPresent) ? function.apply(results) : defaultValue;
        }

        public void execute(Consumer<List<Object>> function) {
            if (allPresent)
                function.accept(results);
        }
    }
public class OptionalsTester {

    public static void main(String[] args) {
        Supplier<Optional<?>> s1 = () -> Optional.of("Hello");
        Supplier<Optional<?>> s2 = () -> Optional.of(1L);
        Supplier<Optional<?>> s3 = () -> Optional.of(55.87);
        Supplier<Optional<?>> s4 = () -> Optional.of(true);
        Supplier<Optional<?>> s5 = () -> Optional.of("World");
        Supplier<Optional<?>> failure = () -> Optional.ofNullable(null);
        Supplier<Optional<?>> s7 = () -> Optional.of(55);

        System.out.print("\nFAILING SEMAPHORES: ");
        new OptionalSemaphores(s1, s2, s3, s4, s5, failure, s7).execute(System.out::println);

        System.out.print("\nSUCCESSFUL SEMAPHORES: ");
        new OptionalSemaphores(s1, s2, s3, s4, s5, s7).execute(System.out::println);
    }

    static class OptionalSemaphores {

        private List<OptionalSupplier> optionalSuppliers;
        private List<Object> results = null;
        private boolean allPresent;

        public OptionalSemaphores(Supplier<Optional<?>>... suppliers) {
            optionalSuppliers = Stream.of(suppliers)
                    .map(OptionalSupplier::new)
                    .collect(Collectors.toList());

            allPresent = optionalSuppliers.stream()
                    .map(OptionalSupplier::getEvaluatedOptional)
                    .allMatch(Optional::isPresent);

            if (allPresent)
                results = optionalSuppliers.stream()
                        .map(OptionalSupplier::getEvaluatedOptional)
                        .map(Optional::get)
                        .collect(Collectors.toList());
        }

        public boolean isAllPresent() {
            return allPresent;
        }

        public <T> T execute(Function<List<Object>, T> function, T defaultValue) {
            return (allPresent) ? function.apply(results) : defaultValue;
        }

        public void execute(Consumer<List<Object>> function) {
            if (allPresent)
                function.accept(results);
        }
    }

    static class OptionalSupplier {

        private final Supplier<Optional<?>> optionalSupplier;
        private Optional<?> evaluatedOptional = null;

        public OptionalSupplier(Supplier<Optional<?>> supplier) {
            this.optionalSupplier = supplier;
        }

        public Optional<?> getEvaluatedOptional() {
            if (evaluatedOptional == null)
                evaluatedOptional = optionalSupplier.get();

            return evaluatedOptional;
        }
    }
}