2016-07-30 278 views
5

我有我已經爲這個問題專門寫了這個例子代碼中使用外部不可變的變量,但它反映了一個真實的情景,我在工作中面臨着:Lambda表達式與表達

List<String> names = Arrays.asList("ALICE", "Alice", "BOB", "Bob", "CHUCK", "Chuck"); 

Predicate<String> has_u_or_i_whenLowercased = Stream.of("u", "i") 
     .map(bit -> (Predicate<String>) (source -> source.toLowerCase(Locale.ENGLISH).contains(bit))) 
     .reduce(Predicate::or) 
     .orElse(p -> false); 

List<String> english = names.stream() 
     .filter(has_u_or_i_whenLowercased) 
     .collect(Collectors.toList()); 
System.out.println(english); 
System.out.println(english.size()); 

它創建一個謂詞,用於檢查源字符串是否包含ui(使用英文區域設置時)(編輯:有十幾種更好更簡單的方法來實現此目的,但這只是一個示例。基於任意數量的搜索標準的小數據集)。我將在一個類的幾個方法中使用這個lambda表達式。

現在,假設我想要一個不同的語言環境,它將作爲參數傳遞給將使用lambda表達式(不是構造函數)的方法。在工作中,它不是我必須處理的區域,但是我將其邊界定義爲不可變變量。

我能想到的最簡單的解決方案是有一個方法「構建」lambda表達式。

@Override 
public void run() { 
    List<String> names = Arrays.asList("ALICE", "Alice", "BOB", "Bob", "CHUCK", "Chuck"); 

    List<String> english = names.stream() 
      .filter(createUIPredicate(Locale.ENGLISH)) 
      .collect(Collectors.toList()); 
    System.out.println(english); 
    System.out.println(english.size()); 

    System.out.println("--"); 

    List<String> turkish = names.stream() 
      .filter(createUIPredicate(new Locale("tr", "TR"))) 
      .collect(Collectors.toList()); 
    System.out.println(turkish); 
    System.out.println(turkish.size()); 
} 

private Predicate<String> createUIPredicate(Locale locale) { 
    return Stream.of("u", "i") 
      .map(bit -> (Predicate<String>) (source -> source.toLowerCase(locale).contains(bit))) 
      .reduce(Predicate::or) 
      .orElse(p -> false); 
} 

但是我覺得這種方法有問題。如果我將一個外部不可變變量注入到函數接口中,我想也許我應該將它作爲lambda表達式參數傳遞給某個地方?

遇到一個lambda表達式,該表達式在表達式中使用了一個外部不可變變量,並且該流不可變變量對於流中間操作中的每個用途可能都不相同,是否存在匹配已知函數編程模式的特定方法?

+2

Predicate的執行過於誇張,不應該使用任何'Stream'的東西。它可以是's - > Pattern.compile(「。* u | i。*」)。matches(s.toLowerCase(locale))''。很容易理解和推理。 – Clashsoft

+0

@Clashsoft''「。* [UIui]。*」''更容易。 – f1sh

+0

「通過它作爲lambda表達式參數」是什麼意思?我認爲你的解決方案是完全合理的。 (但其他方面有些過頭,如其他評論者之前指出的那樣)。確定你可以通過將所有東西都包裝成一種方法來簡化整個事情,並且將它稱爲:'列表 turkish = filterUI(名稱,新Locale(「tr」,「TR」))' – martinhh

回答

1

您的方法解決方案與您的lambda解決方案之間並沒有太多實際的區別,它們都利用lambdas「關閉」「有效的最終」變量。兩者在我寫的Java 8功能代碼中都很常見。

private Predicate<String> build(Locale locale) { 
    return str -> str.toLowerCase(locale); 
} 

與:

Function<Locale, Predicate<String>> build = locale -> str -> str.toLowerCase(locale); 

兩者之間的決定是製造商和/或是否只在一個單一的方法,或在您的類多處使用的風格偏好的只有一個。