2017-02-15 1561 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 –