2017-10-13 84 views
5

請不要「if」語句,除非你解釋爲什麼沒有這個語句是不可能的。Java 8 forEach僅適用於一些?

我看到我可以走多遠只能在流上操作。我有這樣的滋擾:

List<Cube> revised = 
    cubes.filter(p) 
    .map(c -> f(c)) 
    .map(c -> { 
     if(c.prop()) { 
      c.addComment(comment); 
     } 
     return c; 
    }) 
    .collect(Collectors.toList()); 

我對如何做到這一點最好的主意沒有「如果」是

List<Cube> revised = 
    cubes.filter(p) 
    .map(c -> f(c)); 

revised 
    .filter(Cube::prop) 
    .forEach(c -> c.addComment(comment)); // can also map still 

有沒有辦法只有一個鏈做到這一點?如果是的話,分支基本上必須在流中發生。像forSome(predicate, lambda)這樣的方法將工作。

不想「滾我自己」的任何東西。我可以使用「如果」,但我試圖學習如何表達功能風格。

+0

是Optional.ifPresent接受? – VGR

+0

@VGR正是我的想法:) – Eugene

+0

[Collectors.partitioningBy](https://stackoverflow.com/a/30110890/3688648)可能會幫助,如果你想通過'立方體::道具'「發球」你的流# – Felk

回答

3

當您有peek時,不需要使用返回相同元素的map。下面的代碼「祕籍」用短路操作:

cubes.filter(p) 
    .map(c -> f(c)) 
    .peek(c -> c.prop() && c.addComment(comment)) 

我想使用可選的「現代」的方式是遠不如可讀:

cubes.filter(p) 
    .map(c -> f(c)) 
    .peek(c -> Optional.of(c).filter(Cube::prop).ifPresent(c -> c.addComment(comment))) 
+9

假定'addComment'返回'boolean' – Arkadiy

+0

Optional.of(c)風格沒有錯?它似乎嵌套lambda而不是鏈式,即第一個「c」被第二個「c」所遮蔽,儘管在邏輯上它們是相同的。 – djechlin

+3

@djechlin:當然,在範圍內已經有'c'的時候聲明一個新的'c'不起作用。您將不得不使用不同的名稱。 – Holger

1

您可以在以下實現你forSome功能方法:

public static <T> T forSome(T c, Predicate<T> condition, Consumer<T> extraBehaviour) { 

    if (condition.test(c)) { 
     extraBehaviour.accept(c); 
    } 

    return c; 
} 

比你可以使用地圖運營商注入流這樣的:

List<Cube> revised = cubes.stream().filter(p) 
      .map(c -> f(c)) 
      .map(c -> forSome(c, Cube::prop, cube -> cube.addComment("my comment 2"))) 
      .collect(Collectors.toList()); 

只給使用的另一個例子中,我們可以採取下面的例子:

class StudentExam { 
    private final String studentName; 
    private final List<Character> answers; 
    private boolean passed = false; 


    StudentExam(String studentName, List<Character> answers) { 
     this.studentName = studentName; 
     this.answers = answers; 
    } 

    public void markAsPassed() { 
     this.passed = true; 
    } 

    public boolean isPassed() { 
     return passed; 
    } 

    public Character getAnswer(int index) { 
     return answers.get(index); 
    } 

    public String getStudentName() { 
     return studentName; 
    } 
} 

    List<StudentExam> results = asList(
      new StudentExam("John", asList(new Character[] {'A', 'B'})), 
      new StudentExam("Andy", asList(new Character[] {'A', 'C'})), 
      new StudentExam("Mary", asList(new Character[] {'B', 'B'})), 
      new StudentExam("Jane", asList(new Character[] {'C', 'D'})) 
      ); 

現在我們可以,如果正確答案是「A」和「B」比我們可以通過對象流和設置考試的適當狀態。

results.stream() 
      .map(examResult -> forSome(
        examResult, 
        er -> er.getAnswer(0).equals('A') || er.getAnswer(1).equals('B'), 
        StudentExam::markAsPassed)) 
      .forEach(studentExam -> 
        studentExam.getStudentName() + " passed: " + studentExam.isPassed())); 

打印:

  • 約翰:通過真實
  • 安迪:通過真實
  • 瑪麗:通過真實
  • 簡:通過假
相關問題