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?
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
@Clashsoft '' ". * [UIui]. *" '' Jest jeszcze łatwiejsze. – f1sh
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