在 java-8 lambda 表达式中使用 if-else 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42250756/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:02:00  来源:igfitidea点击:

use if-else statement in java-8 lambda expression

javaif-statementlambdajava-8

提问by Shayan Mirzaee

I have a for-statement in java-7 and it's work fine:

我在 java-7 中有一个 for 语句,它工作正常:

Character cha = new Character(',');
String ncourseIds = null;
String pastCourseIds = null;
for (EquivalentCourse equivalentCourse : equivalentCourses) {
  if(equivalentCourse.getNcourse() != null){
    ncourseIds += equivalentCourse.getNcourse().getId()+ ",";   
  } else if(equivalentCourse.getPastCourse() != null) {
    pastCourseIds +=equivalentCourse.getPastCourse().getId()+","; 
  }
}
if(!ncourseIds.isEmpty() &&cha.equals(ncourseIds.charAt(ncourseIds.length()-1))) {
  ncourseIds = ncourseIds.substring(0, ncourseIds.length()-1);
}
if(!pastCourseIds.isEmpty()&& cha.equals(pastCourseIds.charAt(pastCourseIds.length()-1))) {
  pastCourseIds = pastCourseIds.substring(0,pastCourseIds.length()-1);
}

Now I want to convert my code to Stream& collectin java-8, I implement half of my business about filter not null Ncourse:

现在我想将我的代码转换为Stream&collect在 java-8 中,我实现了一半关于 filter not null 的业务Ncourse

equivalentCourses.stream().filter(obj -> obj.getNcourse() != null )
                 .map(obj -> obj.getNcourse().getId()).collect(Collectors.joining(",")); 

but I don't know to implement it's else-statement. any help?

但我不知道实施它的else-statement. 有什么帮助吗?

采纳答案by Joop Eggen

As a stream call chain is complex make two streams - avoiding the conditional branches.

由于流调用链很复杂,所以创建两个流 - 避免条件分支。

String ncourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() != null)
   .map(EquivalentCourse::getNcourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null
          && equivalentCourse.getPastCourse() != null)
   .map(EquivalentCourse::getPastCourse)
   .map(x -> String.valueOf(x.getId()))
   .collect(Collectors.joining(", "));

This also is code focusing on the resulting two strings, with an efficient joining.

这也是专注于生成的两个字符串的代码,具有高效的连接。

By the way, if this is for an SQL string, you may use a PreparedStatement with an Array.

顺便说一句,如果这是用于 SQL 字符串,您可以将 PreparedStatement 与Array一起使用。



Embellishment as commented by @Holger:

@Holger 评论的装饰:

String ncourseIds = equivalentCourses.stream()
   .map(EquivalentCourse::getNcourse)
   .filter(Objects::nonNull)
   .map(NCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));

String pastCourseIds = equivalentCourses.stream()
   .filter(equivalentCourse -> equivalentCourse.getNcourse() == null)
   .map(EquivalentCourse::getPastCourse)
   .filter(Objects::nonNull)
   .map(EquivalentCourse::getPastCourse)
   .map(PastCourse::getId)
   .map(String::valueOf)
   .collect(Collectors.joining(", "));

回答by Cuga

Update

更新

To add an alternative, here's what the code would look like to do the work with two filter()operations. Note, this has the impact of iterating over the entire collection a second time, which may have a performance impact if this is a large collection.

要添加替代方案,以下是使用两个filter()操作完成工作的代码的样子。请注意,这会影响第二次遍历整个集合,如果这是一个大型集合,这可能会对性能产生影响。

I also went ahead and simplified some of the logic in regards to the string joining. Correct me if I missed anything there.

我还继续简化了有关字符串连接的一些逻辑。如果我错过了任何东西,请纠正我。

final List<String> courseIdList = new ArrayList<>();
final List<String> pastCourseIdList = new ArrayList<>();

equivalentCourses.stream().filter((current) -> current.getNcourse() != null)
                .forEach((current) -> courseIdList.add(current.getNcourse().getId()));

equivalentCourses.stream().filter((current) -> current.getNcourse() != null && current.getPastCourse() != null)
                .forEach((current) -> pastCourseIdList.add(current.getPastCourse().getId()));

String ncourseIds = String.join(",", courseIdList);
String pastCourseIds = String.join(",", pastCourseIdList);

Original answer

原答案

For your use case, it may make the most sense to use the forEach()lambda. This will be the easiest way to do the translation.

对于您的用例,使用forEach()lambda可能最有意义。这将是最简单的翻译方法。

java.lang.Character cha = new java.lang.Character(',');

final StringBuilder ncourseIdBuilder = new StringBuilder();
final StringBuilder pastCourseIdBuilder = new StringBuilder();
equivalentCourses.stream().forEach((equivalentCourse) -> {
    if (equivalentCourse.getNcourse() != null) {
        ncourseIdBuilder.append(equivalentCourse.getNcourse().getId()).append(",");
    } else if (equivalentCourse.getPastCourse() != null) {
        pastCourseIdBuilder.append(equivalentCourse.getPastCourse().getId()).append(",");
    }
});

String ncourseIds = ncourseIdBuilder.toString();
String pastCourseIds = pastCourseIdBuilder.toString();

if (!ncourseIds.isEmpty() && cha.equals(ncourseIds.charAt(ncourseIds.length() - 1))) {
    ncourseIds = ncourseIds.substring(0, ncourseIds.length() - 1);
}
if (!pastCourseIds.isEmpty() && cha.equals(pastCourseIds.charAt(pastCourseIds.length() - 1))) {
    pastCourseIds = pastCourseIds.substring(0, pastCourseIds.length() - 1);
}

You can rewrite the code using filter()expressions, but it'll require a bigger re-working of the logic in the conditionals, which introduces the risk you might break something if this isn't tested well. The logic changes are exactly what @Holger and @Ole V.V. reference in their comments to the original question.

您可以使用filter()表达式重写代码,但它需要对条件中的逻辑进行更大的重新设计,这会带来风险,如果没有很好地测试,您可能会破坏某些东西。逻辑变化正是@Holger 和@Ole VV 在他们对原始问题的评论中所引用的内容。

Whether you use forEach()or the filters, lambdas cannot access non-final variables within the expression, hence why I added the final StringBuildervariable outside the scope of the loop.

无论您使用forEach()过滤器还是过滤器,lambda 都无法访问表达式中的非最终变量,因此我将final StringBuilder变量添加到循环范围之外。

回答by Kozio?ek

You could group by condition and then remap:

您可以按条件分组,然后重新映射:

public void booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");

    strings.stream()
            .collect(
                    Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey() ? "Present" : "Past",
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

First stream group by condition, you should use equivalentCourse.getNcourse() != nullsecond remap collections from value to string. You could introduce:

第一个按条件分组的流,您应该使用equivalentCourse.getNcourse() != null从值到字符串的第二个重新映射集合。你可以介绍:

enum PresentPast{
    Present, Past
    PresentPast is(boolean v){
         return v ? Present : Past
    }
}

and change e -> e.getKey() ? "Present" : "Past"to enum based solution.

并更改e -> e.getKey() ? "Present" : "Past"为基于枚举的解决方案。

Edit:

编辑:

Solution for else if:

解决方案else if

public Map<Classifier, String> booleanGrouping() throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("ala");
    strings.add("ela");
    strings.add("jan");
    // our ifs:
    /*
        if(!string.endsWith("n")){
        }else if(string.startsWith("e")){}

        final map should contains two elements
        endsWithN -> ["jan"]
        startsWithE -> ["ela"]
        NOT_MATCH -> ["ala"]

     */
    return strings.stream()
            .collect(
                    Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate
            ).entrySet()
            .stream()
            .collect(
                    Collectors.toMap(
                            e -> e.getKey(),
                            e -> e.getValue().stream().collect(Collectors.joining(""))
                    )
            );
}

enum Classifier implements Predicate<String> {
    ENDS_WITH_N {
        @Override
        public boolean test(String s) {
            return s.endsWith("n");
        }
    },
    STARTS_WITH_E {
        @Override
        public boolean test(String s) {
            return s.startsWith("e");
        }
    }, NOT_MATCH {
        @Override
        public boolean test(String s) {
            return false;
        }
    };

    public static Classifier apply(String s) {
        return Arrays.stream(Classifier.values())
                .filter(c -> c.test(s))
                .findFirst().orElse(NOT_MATCH);
    }
}