IntelliJ - 方法引用可能会改变语义

str*_*tle 5 java lambda intellij-idea

我有以下代码:

return userService.getAll()
    .stream()
    .map(User::getRoleName)
    .map(roleName -> roleService.findRoleByName(roleName))
    .collect(Collectors.toSet());
Run Code Online (Sandbox Code Playgroud)

似乎roleName -> roleService.findRoleByName(roleName)可以用方法引用(即对特定对象的实例方法的引用)替换,但是 IntelliJ IDEA 警告说这可能会改变语义:

截屏

它如何改变语义?它会改变语义吗?

Don*_*nat 5

如果您不遵循干净函数式编程的规则,则当您将 lambda 转换为方法引用时,语义可能会发生变化。

不同之处在于,方法引用仅在构建流时解析一次。但在 lambda 表达式中,可以在每次执行 lambda 时计算用于获取方法的代码。

这是一个简短的独立示例用于演示:

public class Test40 {
  public static void main(String[] args) {
    Function<Integer, Integer> f2 = n -> 2 * n;
    Function<Integer, Integer> f3 = n -> 3 * n;
    Function<Integer, Integer>[] funcArray = new Function[1];

    funcArray[0] = f2;
    Stream.of(1, 2, 3)
          .peek(n -> { if (n > 1) funcArray[0] = f3; })
          .map(funcArray[0]::apply)            // Method reference, '::apply' could be omitted
          .forEach(System.out::print);         // prints 246
    System.out.println();

    funcArray[0] = f2;
    Stream.of(1, 2, 3)
          .peek(n -> { if (n > 1) funcArray[0] = f3; })
          .map(n -> funcArray[0].apply(n))     // Lambda
          .forEach(System.out::print);         // prints 269
    System.out.println();
  }
}
Run Code Online (Sandbox Code Playgroud)

如何避免此问题:使用流时不要使用副作用。请勿用于peek加工!这个方法的存在主要是为了支持调试(看看javadoc)。