2016-07-30 9 views
5

mam ten przykładowy kod, który napisałem specjalnie do tego pytania, ale odzwierciedla prawdziwy scenariusz I stanęła w miejscu pracy:lambda wyrażenia z zewnętrznych zmiennych niezmiennych stosowanych w wyrażeniu

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()); 

Stwarza predykat sprawdzający, czy źródłowy ciąg zawiera u lub i, gdy jest pisany małymi literami z angielskimi ustawieniami narodowymi (EDYCJA:Istnieje kilkanaście lepszych i prostszych sposobów wdrożenia tego, ale to tylko przykład. W prawdziwym scenariuszu filtruję mały zestaw danych oparty na arbitralnej liczbie kryteriów wyszukiwania). Zamierzam użyć tego wyrażenia lambda dla kilku metod klasy.

Załóżmy teraz, że chcę mieć inne ustawienia narodowe, które zostaną przekazane jako argument do metody, która użyje wyrażenia lambda (nie konstruktora). W pracy nie mam Locale, z którym mam do czynienia, ale zdefiniowałem jego granicę jako niezmienną zmienną.

Najprostszym rozwiązaniem, jakie mogłem wymyślić, było zastosowanie metody "budowania" tego wyrażenia 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); 
} 

Jednak mam wrażenie, że coś jest nie tak z tym podejściem. Jeśli wstawiam zewnętrzną niezmienną zmienną do funkcjonalnego interfejsu, pomyślałem, że może powinienem podać ją jako argument wyrażenia lambda zamiast gdzieś?

W przypadku skonfrontowania z wyrażeniem lambda, które zawiera zewnętrzną niezmienną zmienną użytą w wyrażeniu, i że niezmienna zmienna może być różna dla każdego użycia w ramach operacji pośredniej strumienia, czy istnieje konkretne podejście, które pasuje do znanego wzorca programowania funkcjonalnego?

+2

Implementacja predykatu jest przesadą i nie powinna używać żadnych rzeczy typu "Stream". Może to być po prostu 's -> Pattern.compile (". * U | i. * "). Matches (s.toLowerCase (locale))'. DUŻO łatwiej zrozumieć i uzasadnić. – Clashsoft

+0

@Clashsoft '' ". * [UIui]. *" '' Jest jeszcze łatwiejsze. – f1sh

+0

Co masz na myśli przez "przekazać go jako argument wyrażenia lambda"? Myślę, że twoje rozwiązanie jest całkowicie rozsądne. (Ale nieco przesadzone pod innymi względami, jak wskazali wcześniej inni komentatorzy). Oczywiście możesz uprościć całość jeszcze bardziej, pakując wszystko w jedną metodę i nazywając to tak: 'List turkish = filterUI (nazwy, nowe ustawienia regionalne (" tr "," TR "))' – martinhh

Odpowiedz

1

Nie ma tak naprawdę praktycznej różnicy między rozwiązaniem twojej metody a twoim rozwiązaniem lambda z komentarzy, obie wykorzystują lambdy "zamykające" "efektywnie końcowe" zmienne. Oba są dość powszechne w napisanym przeze mnie kodzie funkcjonalnym Java 8.

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

kontra:

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

Decyzję między nimi jest tylko jednym preferencji stylu i/lub czy budowniczym jest używana tylko w obrębie jednej metodzie lub w wielu miejscach w swojej klasie.