如何连接两个可选<;字符串>;在Java8中使用分隔符

如何连接两个可选<;字符串>;在Java8中使用分隔符,java,java-8,optional,Java,Java 8,Optional,我有两个可选的字符串,name1和name2。我想加入这两个选项,这样结果也是可选的: 如果其中一个为非空,则结果应为非空名称 如果两者都非空,我希望结果与分隔符和合并 如果两者都为空,则结果应为空可选 我的尝试是: StringBuilder sb = new StringBuilder(); name1.ifPresent(sb::append); name2.ifPresent(s -> { if (sb.length() > 0) { sb.appen

我有两个
可选的
字符串,
name1
name2
。我想加入这两个选项,这样结果也是可选的:

  • 如果其中一个为非空,则结果应为非空名称
  • 如果两者都非空,我希望结果与分隔符
    合并
  • 如果两者都为空,则结果应为空
    可选
  • 我的尝试是:

    StringBuilder sb = new StringBuilder();
    name1.ifPresent(sb::append);
    name2.ifPresent(s -> {
        if (sb.length() > 0) {
            sb.append(" AND ");
        }
        sb.append(s);
    }
    Optional<String> joinedOpt = Optional.ofNullable(Strings.emptyToNull(sb.toString()));
    
    StringBuilder sb=新建StringBuilder();
    名称1.如果存在(sb::追加);
    名称2.如果存在(s->{
    如果(sb.length()>0){
    某人附加(“及”);
    }
    某人追加;
    }
    Optional joinedOpt=Optional.ofNullable(Strings.emptyToNull(sb.toString());
    
    这是可行的,但看起来很难看,也不太实用


    PS:有一个类似的答案,但被接受的答案是错误的。具体地说,如果
    name1
    为空而
    name2
    为空,它将返回一个空的可选值。

    Java 1.9中可能的解决方案是

     Optional<String> name1 = Optional.of("x");
     Optional<String> name2 = Optional.of("y");
     String s = Stream.concat(name1.stream(), name2.stream()).collect(Collectors.joining(" AND "));
     System.out.println(s);
    

    这里是一个流式解决方案,它过滤存在的
    可选
    元素,然后提取元素并使用内置收集器加入其余元素。然后它测试结果是否为空,以返回空的
    可选

    它接受一个
    列表
    可选
    s,因此它涵盖了比两个元素更一般的情况

    public Optional<String> optionalJoin(List<Optional<String>> strings) {
        String result = strings.stream()
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.joining(" AND "));
        return result.isEmpty() ? Optional.empty() : Optional.of(result);
    }
    
    public可选选项连接(列表字符串){
    字符串结果=strings.stream()
    .filter(可选::isPresent)
    .map(可选::get)
    .收款(收款人加入(“和”);
    返回result.isEmpty()?Optional.empty():Optional.of(result);
    }
    
    一个无流的衬里,但不是特别优雅:

        public static Optional<String> concat(Optional<String> name1, Optional<String> name2) {
            return Optional.ofNullable(name1.map(s1 -> name2.map(s2 -> s1 + " AND " + s2).orElse(s1)).orElse(name2.orElse(null)));
        }
    
        public static void main(String[] args) {
            System.out.println(concat(Optional.of("A"), Optional.of("B")));
            System.out.println(concat(Optional.of("A"), Optional.empty()));
            System.out.println(concat(Optional.empty(), Optional.of("B")));
            System.out.println(concat(Optional.empty(), Optional.empty()));
        }
    
    public静态可选concat(可选名称1,可选名称2){
    返回可选的.ofNullable(name1.map(s1->name2.map(s2->s1+”和“+s2).orElse(s1)).orElse(name2.orElse(null));
    }
    公共静态void main(字符串[]args){
    系统输出打印LN(concat(可选的of(“A”)、可选的of(“B”));
    System.out.println(concat(可选的.of(“A”),可选的.empty());
    System.out.println(concat(Optional.empty(),Optional.of(“B”)));
    System.out.println(concat(可选的.empty(),可选的.empty());
    }
    
    一种解决方案是流式处理和
    reduce()

    Optional joinedOpt=Stream.of(name1,name2)
    .filter(可选::isPresent)
    .map(可选::get)
    .减少((a,b)->a+”和“+b);
    

    您可以按照其他人的建议,用Java 9或番石榴替换过滤器/映射组合。

    有时,尝试使用
    可选
    (或
    )实现功能只会模糊您试图在代码中表达的内容

    对我来说,这里的主要思想是,如果两个值都存在,那么它们应该用“AND”连接起来。下面是一个重点:

    Optional<String> joinedOpt;
    if (name1.isPresent() && name2.isPresent()) {
        joinedOpt = Optional.of(name1.get() + " AND " + name2.get());
    } else {
        joinedOpt = name1.isPresent() ? name1 : name2;
    }
    
    可选连接点;
    if(name1.isPresent()&&name2.isPresent()){
    joinedOpt=Optional.of(name1.get()+”和“+name2.get());
    }否则{
    joinedOpt=name1.isPresent()?name1:name2;
    }
    

    我可能误解了他的信息,但这种方法的灵感来源于他在帮助设计
    可选
    时所做的选择。他使用
    收集器设计了略微不同的风格。加入

        Optional<String> result  = Optional.of( 
            Stream.of(so1, so2)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect( Collectors.joining(" AND ") ) 
        ).filter( s -> !s.isEmpty() ); 
    
    Optional result=Optional.of(
    (so1、so2)的流量
    .filter(可选::isPresent)
    .map(可选::get)
    .收集(收集器。连接(“和”))
    ).filter(s->!s.isEmpty());
    

    我喜欢
    收集器。加入
    是因为Java streams可以潜在地重用单个StringBuilder类,而不是在执行
    +
    操作时创建一个新的类。

    接近公认的答案

    Optional<String> joinedOpt = Stream.of(name1, name2)
                .flatMap(x -> x.map(Stream::of).orElse(null))
                .reduce((a, b) -> a + " AND " + b);
    
    Optional joinedOpt=Stream.of(name1,name2)
    .flatMap(x->x.map(Stream::of).orElse(null))
    .减少((a,b)->a+”和“+b);
    
    或者在java-9中:

    Optional<String> joinedOpt = Stream.of(name1, name2)
                .flatMap(Optional::stream)
                .reduce((a, b) -> a + " AND " + b);
    
    Optional joinedOpt=Stream.of(name1,name2)
    .flatMap(可选::流)
    .减少((a,b)->a+”和“+b);
    
    Nice!我想在Java中也可以用番石榴做同样的事情8@spinlok是的,如果番石榴是可用的,那么您可以进行排序。当两者都为空时,这不会返回空的可选项。@SleimanJneidi还有为什么会有
    orElseGet
    而不是
    orElse(Stream.empty())
    ,这不像创建一个空流是昂贵的。请同时假设代码工作正常,您可能希望以更完整的方式编写您的示例,并在上征求评论。请务必先阅读,因为那里有些事情的处理方式不同!我花了一些时间来理解此解决方案,因此它在从某种意义上说,它确实起到了作用,但在我看来,理解起来有点费时,所以可读性很低。当我说可读性时,我的意思是“另一个人”可以看着代码说“啊,这就是它的功能”。但这可能只是我…@Aominè。我认为这只是个人观点。对我来说,这看起来是一个干净易读的解决方案。可能是因为过去的MapReduce工作。我唯一的意见是在每个元素上创建太多中间
    StringBuilder
    对象,而不是在使用
    收集器时可能重用单个对象。jOing
    @tsolakp是的,这是一个基于意见的评论。顺便说一句,我喜欢这个答案;-)。无论如何,我唯一的意见是在每个元素上创建太多的中间StringBuilder对象,而不是在使用Collectors.joining时可能重用单个对象,请记住,我们最多有2个(加上“和”)字符串对象,因此可能不值得使用
    StringBuilder
    。串联总是在后台使用StringBuilder。但是这个减少最多只能调用一次。@shmosel不总是,startin
        Optional<String> result  = Optional.of( 
            Stream.of(so1, so2)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect( Collectors.joining(" AND ") ) 
        ).filter( s -> !s.isEmpty() ); 
    
    Optional<String> joinedOpt = Stream.of(name1, name2)
                .flatMap(x -> x.map(Stream::of).orElse(null))
                .reduce((a, b) -> a + " AND " + b);
    
    Optional<String> joinedOpt = Stream.of(name1, name2)
                .flatMap(Optional::stream)
                .reduce((a, b) -> a + " AND " + b);