Lambda expressions with external immutable variables used in the expression

I have this sample code that I wrote specifically for this question, but it reflects the real scenario that I came across at work:

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

It creates a predicate that checks if the source string contains u or i if lowercase with English ( EDIT: there are a dozen best and easiest ways to implement this, but this is just an example. In a real scenario, I filter a small data set based on arbitrary number of search criteria). I am going to use this lambda expression for several class methods.

Now suppose I want to have another locale that will be passed as an argument to a method that will use the lambda expression (and not the constructor). At work, this is not the language I have to deal with, but I defined its boundary as an immutable variable.

The simplest solution I could think of was to have the build method create this lambda expression.

 @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); } 

However, I feel that something is wrong with this approach. If I introduce an external immutable variable into a functional interface, I thought that perhaps I should pass it as an argument to the lambda expression instead of something?

When faced with a lambda expression that has an external immutable variable used in the expression, and that the immutable variable can be different for each use in the intermediate flow operation, is there a concrete approach that matches the well-known functional programming pattern?

+5
source share
1 answer

There is not much practical difference between your method solution and your lambda solution from the comments, both take advantage of the lambda "closure" of the "effectively finite" variables. Both are pretty common in the Java 8 functional code I wrote.

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

vs

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

The solution between them is only one of the style preferences and / or this builder is used only within the framework of one method or in several places of your class.

+1
source

All Articles