如何在命名的Java Lambda Expressions中使用其他变量,就像我可以用匿名变量一样?我找到了一个解决方法(方法返回一个Lambda),但出于好奇:这是否也可以用纯Lambda语法表达?我在常用的教程和参考资料中找不到答案。
请考虑以下示例代码:
Arrays.asList(1,2,3,4,5).stream().filter( i -> i<3 ).toArray();
我可以给这个匿名的Lambda命名:
Arrays.asList(1,2,3,4,5).stream().filter(LessThanThree).toArray();
[...]
Predicate<Integer> LessThanThree = i -> i<3;
但是如果我想使用变量而不是常量,则相同的语法将不起作用。因为我找不到一种方法来声明名为Lambda的参数:
编辑:谢谢你,dpr,暗示这是一个范围问题!我增强了以下代码块,试图澄清我感兴趣的内容。
filterIt(3);
[...]
void filterIt(int x) {
Arrays.asList(1,2,3,4,5).stream().filter(LessThanX).toArray();
}
[...]
Predicate<Integer> LessThanX = i -> i<x; // won't compile!
解决方法似乎是一个返回Lambda的方法:
private Predicate<Integer> lessThanX(int x) {
return i -> i<x;
}
但是:有没有办法用纯名为Lambda的方法来制定它?
答案 0 :(得分:4)
在您的情况下,您可以使用BiPredicate<Integer, Integer> lessThan = (i, j) -> i < j;
Arrays.asList(1,2,3,4,5).stream().filter(i -> lessThan.test(i, 3)).collect(Collectors.toList());
代替正常谓词
@FunctionalInterface
如果您需要使用2个以上输入的测试,则可能需要编写自己的POSTGRESQL_USER
POSTGRESQL_PASSWORD
POSTGRESQL_DATABASE
作为lambda。
答案 1 :(得分:1)
如果添加第二个变量(例如示例中的x),则不再有Predicate<Integer>
。你有一个BiFunction<Integer,Integer,Boolean>
(即一个带有两个参数的函数,返回一个Boolean
)。
您可以定义lambda表达式并将其指定给BiFunction<Integer,Integer,Boolean>
:
BiFunction<Integer,Integer,Boolean> LessThanX = (i,x) -> i<x;
为了将其转换为Predicate<Integer>
,您需要第二个依赖于第一个的lambda表达式:
Predicate<Integer> LessThan3 = i -> LessThanX.apply (i, 3);
当然,您可以直接使用BiFunction
:
Arrays.asList(1,2,3,4,5).stream().filter(i -> LessThanX.apply (i, 3)).toArray();
答案 2 :(得分:1)
请注意,此lambda:a -> a < b
只接受一个参数 - a
。 x
的值被烘焙到函数中。
在循环中使用它时:
for(int b = 0; b<20; b++) {
IntStream.range(15,25)
.filter( a -> a < b)
...;
}
您每次围绕b
循环创建新谓词:
a -> a < 0
a -> a < 1
a -> a < 2
......等等。在此示例中,如果b
不是有效的最终,编译器将禁止它。
您可以通过定义本地Predicate
:
for(int b = 0; b<20; b++) {
Predicate<Integer> lessThanB = a -> a < b;
IntStream.range(15,25)
.filter(lessThanB)
...;
}
但是你不能在b
是最终变量的范围之外定义lessThanB。
您可以定义BiPredicate
:
BiPredicate<Integer,Integer> lessThan = (a,b) -> a < b;
...但您无法在BiPredicate
处使用Predicate
- 例如在Stream.filter()
。 Currying 将BiPredicate
变为Predicate
,其中一个参数被烘焙:
final int x = 5;
Predicate<Integer> lessThanX = n -> lessThan.test(n,x);
...您可以在filter()
:
.filter( n -> lessThan.test(n,x))
但是,您获得的收益并不高 - 您仍在为Predicate
的每个新值创建新的x
。
没有TriPredicate
但FP的原则是 n 单参数函数链相当于一个 n -param函数。您不需要多个参数(BiPredicate
是礼貌的)
即代替:
TriFunction<String, String, String, User> finder = (company, dept, name) -> { ...}`
......你有:
Function<String, Function<String, Function<String, User>>> format =
company -> dept -> name ->
String.format("Company: %s\nDept: %s\nName: %s", company, dept, name);
被称为String s = format.apply("Daimler").apply("Accounts").apply("John Doe")
...或者更不常见的是,三个参数Predicate
将是:
Function<String, Function<String, Predicate<String>>> userExists =
company -> dept -> name -> somethingThatReturnsBoolean(company, dept, name);
......被称为:
boolean exists =
userExists.apply("Daimler").apply("Accounts").test("John Doe")
答案 3 :(得分:0)
此代码编译!
int x = 3;
Predicate<Integer> LessThanThree = i -> i<x;
Arrays.asList(1,2,3,4,5).stream().filter(LessThanThree).toArray();
请记住,x必须是effectively final!
只要你添加另一行x = 4
就会中断。
答案 4 :(得分:0)
您的代码段已经完美无缺。
data
我更喜欢它是方法而不是变量coz,该方法赋予操作或比较更多的意义。对于这种检查大小而不是影响的小案例,当然是一个真实案例场景,方法更好,它还允许您在 List<Integer> vals = Arrays.asList(1,2,3,4,5);
int compare_int = 2;
//Add this compare_int = 4;//Variable used in lambda expression should be final or effectively final
Predicate<Integer> GT_3 = integer -> integer > compare_int;
System.out.println(vals.stream().filter(GT_3).count());//prints 3
方法中共享。