2016-11-21 52 views
2

我有一個功能,在List上執行一些流操作(特別是過濾器)。如何將Stream操作參數添加到我的函數中?

public List<String> getAndFilterNames(List<Person> people, Predicate<Person> nameFilter){ 
    List<String> allNames = people.stream() 
    .map(person -> person.getName()) 
    .filter(nameFilter) 
    .collect(Collectors.toList()); 
    return allNames; 
} 

我希望能夠通過中間流操作(filterdistinct等)和有我的功能運行的終端操作之前執行該操作。例如:

public List<String> getAndProcessNames(List<Person> people, <intermediate stream operation>){ 
    List<String> allNames = people.stream() 
    .map(person -> person.getName()) 
    // perform <intermediate stream operation> here 
    .collect(Collectors.toList()); 
    return allNames; 
} 

雖然,根據我目前的經驗水平,這似乎是不可能的。有些中間操作有一個參數(如filter),而另一些則沒有(如distinct),所以我不能設置一個處理所有情況的單個參數類型......我想我可以創建幾個簽名,使用FunctionSupplier

即使這樣,該功能界面與參數的功能需要改變... filter需要Predicatemap需要Function,並從我的理解,是沒有辦法來表示一個通用的功能接口。那是對的嗎?沒有實際的共同課堂或界面,他們都從中吸取。

那麼,到底,看來我最好的選擇是隻mapcollect,然後運行我的期望流操作的情況下,逐案的基礎,如:

public List<String> getNames(List<Person> people){ 
    List<String> allNames = people.stream() 
    .map(person -> person.getName()) 
    .collect(Collectors.toList()); 
    return allNames; 
} 

List<Person> employees = // a bunch of people 
List<String> employeeNames = getNames(employees); 
employeeNames = employeeNames.stream(). // desired operations 

編輯 :或者,按@Holger:

public Stream<String> getNamesStream(List<Person> people){ 
    Stream<String> namesStream = people.stream() 
    .map(person -> person.getName()); 
    return namesStream; 
} 

List<Person> employees = // a bunch of people 
Stream<String> employeeNamesStream = getNamesStream(employees); 
employeeNamesStream(). // desired operations 

或者是否有我遺失的東西?

回答

11

你想要的是一個功能從StreamStream。例如:

public List<String> processNames(Function<Stream<String>, Stream<String>> f) { 
    return f.apply(people.stream().map(Person::getName)) 
      .collect(toList()); 
} 

然後調用,如:

List<String> filteredNames = processNames(s -> s.filter(n -> n.startsWith("A"))); 
+2

那麼,唯一的「優勢」是調用者被迫接收一個收集的List,而不是被允許鏈接自己的終端操作。並且該函數不允許映射到除「String」之外的其他內容。我認爲這是一種反收集模式,是以收集爲中心的觀點造成的。另外,應該提到只是返回流以允許任意後續操作。 – Holger

+3

OP想知道是否有任何方法將「流操作」作爲數據傳遞。 「通過一元運算符」的習語一開始並不明顯,有時也很有用。在這種情況下是否值得是無關緊要的(並且挑剔這是否是正確的應用地點似乎是故意忽略了這一點)。這裏的要點是,從「傳遞流操作」到「傳遞修改流的方式」是一個有用的工具,在您的工具箱中有明顯的需求,而且這些工具顯然還沒有出現OP(和其他)。 –

+1

我並不反對說這個解決方案,我只是建議告​​訴另一個顯然還沒有出現的解決方案,並且可能解決實際問題,因爲這看起來很像xy問題。 – Holger

0

是的,你是對的。沒有中間操作可以擴展的通用基本接口,但由於它們實際執行的操作不同,所以不應該有一個。

可以創建一些方法,你可以鏈的電話:

private static <T> Stream<T> applyPredicates(Stream<T> input, List<Predicate<T>> predicates) { 
    Stream<T> result = Stream.concat(input, Stream.empty()); 
    for (Predicate<T> pred : predicates) { 
      result = result.filter(pred); 
    } 
    return result; 
} 

/** 
    * this could be modified to accept more then one parameters 
    */ 
private static <T, R> Stream<R> applyFunction(Stream<T> input, Function<T, R> function) { 
    return input.map(function); 
} 

再例如:

List<String> list = Arrays.asList("one", "two", null, "three"); 

    Predicate<String> p1 = t -> t != null; 
    Predicate<String> p2 = t -> t.startsWith("t"); 

    applyFunction(applyPredicates(list.stream(), Arrays.asList(p1, p2)), String::length) 
      .collect(Collectors.toList()); 

注意applyFunctions將不得不超負荷採取多種功能爲輸入參數,因爲每個映射操作可能會將流從T更改爲R,然後更改爲Y等等。

+0

這是一個很好的開始=)希望我們都在這裏學到了一些東西 –

相關問題