在表达式中使用外部不可变变量的Lambda表达式

Hay*_*Hay 5 java 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());
Run Code Online (Sandbox Code Playgroud)

它创建了一个谓词,用于检查源字符串是否包含u或者i何时使用英语语言环境进行小写(编辑: 有十几个更好,更简单的方法来实现它,但这仅仅是一个例子.在真实场景中我正在过滤一个小数据根据任意数量的搜索条件设置).我将在类的几个方法中使用这个lambda表达式.

现在,假设我想要一个不同的语言环境,它将作为参数传递给将使用lambda表达式(而不是构造函数)的方法.在工作中,它不是我必须处理的Locale,但我将其边界定义为不可变变量.

我能想到的最简单的解决方案是使用一个方法"构建"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);
}
Run Code Online (Sandbox Code Playgroud)

但是我觉得这种方法有问题.如果我将一个外部不可变变量注入一个函数接口,我想也许我应该把它作为一个lambda表达式参数传递给某个地方?

当遇到lambda表达式时,表达式中使用了外部不可变变量,并且对于流中间操作中的每次使用,该不可变变量可能不同,是否有一种与已知函数编程模式匹配的特定方法?

小智 1

从注释来看,您的方法解决方案和 lambda 解决方案之间并没有太大的实际区别,两者都利用 lambda“关闭”“有效最终”变量。这两种情况在我编写的 Java 8 函数代码中都很常见。

private Predicate<String> build(Locale locale) {
  return str -> str.toLowerCase(locale);
}
Run Code Online (Sandbox Code Playgroud)

相对:

Function<Locale, Predicate<String>> build = locale -> str -> str.toLowerCase(locale);
Run Code Online (Sandbox Code Playgroud)

两者之间的决定只是风格偏好和/或该构建器是否仅在单个方法中使用或在类中的多个位置使用之一。