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

时间:2017-02-15 13:29:29

标签: java if-statement lambda java-8

我在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);
}

现在我想将我的代码转换为Stream& java-8中的collect,我实现了一半关于过滤器的业务,而不是Ncourse

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

但我不知道要实现它else-statement。有什么帮助吗?

3 个答案:

答案 0 :(得分:4)

由于流调用链很复杂,需要两个流 - 避免条件分支。

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(", "));

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

顺便说一句,如果这是一个SQL字符串,您可以使用带有Array的PreparedStatement。

@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(", "));

答案 1 :(得分:1)

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

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(""))
                    )
            );
}

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

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

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

编辑:

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);
    }
}

答案 2 :(得分:0)

<强>更新

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

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

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);

原始回答

对于您的用例,使用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);
}

您可以使用filter()表达式重写代码,但它需要在条件语句中更大程度地重新处理逻辑,如果不是这样,则会引入您可能会破坏某些内容的风险测试得很好。逻辑上的变化正是@Holger和@Ole V.V.在对原始问题的评论中提及。

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