2017-02-15 1558 views
2

我有一个for语句中的Java-7,它的做工精细:使用的if-else在Java的8 lambda表达式语句

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 & collect在Java的8,我实现了我的业务的一半左右过滤器不为空Ncourse

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

,但我不知道要实现它的else-statement。任何帮助?

+4

为什么你使用'Character'代替'char'?这会让你的代码更难阅读*和*浪费资源。尽管如此,如果用一个简单的'ncourseIds.endsWith(“,)代替'!ncourseIds.isEmpty()&& ha.equals(ncourseIds.charAt(ncourseIds.length() - 1))',你根本不需要它。 “)'同样,''pastCourseIds.isEmpty()&& cha.equals(pastCourseIds.charAt(pastCourseIds.length() - 1))''与'pastCourseIds.endsWith(”,“)'。要用流收集两个字符串,可以简单地执行两个流操作。 – Holger

+3

@Holger已经说过:使用两个流操作(一个用于'getNcourse()!= null')和一个用于'getNcourse()== null && getPastCourse()!= null')。 –

回答

3

由于流调用链是复杂的,因此会生成两个流 - 避免出现条件分支。

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字符串,您可以使用PreparedStatement与Array


点缀的评论说@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(", ")); 
+0

很好用的双冒号! – Cuga

+2

您可以通过更改顺序进行简化。第一个流op:'.map(EquivalentCourse :: getNcourse).filter(Objects :: nonNull)',第二个流op:'.filter(equivalentCourse - > equivalentCourse.getNcourse()== null).map(EquivalentCourse :: getPastCourse ).filter(Objects :: nonNull)'。 – Holger

+1

@Holger你是对的,而且getId也可以通过一些类的知识来改进 –

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()拉姆达最有意义。这将是翻译最简单的方法。

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()还是过滤器,lambda表达式都不能访问表达式内的非最终变量,因此为什么我在循环范围之外添加了final StringBuilder变量。

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

这个解决方案只适用于'if-else'语句,但问题是关于'else-if'语句。在这种情况下,您需要执行两个流操作。 – MBec

+0

我明白了:)当我回到主PC时,我会解决这个问题(你需要介绍一些不同的条件):D –