[英]How to return a lambda function and use by passing as an argument to a method in Java 8? Why I can't use :: operator?
我试图在我的 Role 类中实现自定义验证谓词。 即isInRealm()
它返回一个Predicate<String>
并且是一个基本的,只是为了表明我的意图。
public enum Role {
USER("ROLE_user", 1),
CUSTOMER("ROLE_customer", 2),
//...
public static Predicate<String> isInRealm() {
return role -> Arrays.stream(values()).anyMatch(value -> value.value.equals(role));
}
}
我可以在客户端类中定义谓词,也可以直接作为 lambda 表达式或方法引用传递。(1)(2) 下面,有它们的情况,我已经注意到哪个有效或无效。
public class UserService {
//...
public User getUserProfile() {
//validateUser(Role.isInRealm()); -> OK
validateUser(Role::isInRealm); -> NOK
validateUser(r -> Role.isInRealm()); -> NOK
//validateUser(role -> Arrays.stream(Role.values()).anyMatch(value -> value.equals(role))); -> OK (1)
//validateUser(s -> true); -> OK (2)
//...
}
private void validateUser(Predicate<String> predicate) {
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
String role = utils.getRoles(principal).findFirst().get().getAuthority();
if (!predicate.test(role)) {
throw new ForbiddenAccessException(ResponseCode.FORBIDDEN_ACCESS.getMessage());
}
}
}
我对如何获取从方法返回的Function
的句柄感到困惑。
虽然isInRealm()
方法返回一个 lambda 表达式作为谓词,为什么我不能用Role::isInRealm
或r -> Role.isInRealm()
调用它? 当我尝试时,我bad return type in lambda expression: Predicate<String> cannot be converted to boolean
收到错误bad return type in lambda expression: Predicate<String> cannot be converted to boolean
的错误bad return type in lambda expression: Predicate<String> cannot be converted to boolean
。
当我直接在客户端代码中传递 lambda 表达式时,它可以工作,但在这种情况下,我需要使用validateUser(Role.isInRealm())
获取返回的函数。 为什么会这样?
Role.isInRealm()
是有道理的,因为该方法返回一个我们正在获取对象的函数对象,但由于 Java 8 流 API 函数不是一流的语言构造,我无法完全掌握使用::
获取它时发生的情况。
当我们得到点或双冒号时,后面发生了什么?
您将 lambda 与调用混合在一起。 在以下示例中调用isInRealm
,并使用返回值 (lambda):
validateUser(Role.isInRealm());
如此有效的role -> Arrays.stream(values()).anyMatch(value -> value.value.equals(role));
传递给validateUser
方法。
在接下来的两个例子中:
validateUser(Role::isInRealm);
validateUser(r -> Role.isInRealm());
您正在尝试传递 lambdas(供应商),调用时将返回您正在寻找的 lambda。 您没有将Predicate
传递给validateUser
。
方法validateUser
需要Predicate<String>
,因此方法句柄( ::
语法)和 lambda 必须符合该功能接口。
对于符合Predicate<String>
的方法句柄,可以匹配三种可能的方法签名(和返回类型):
String
类中的(非静态) boolean methodName()
,简称String::methodName
boolean methodName(String value)
被称为ClassName::methodName
boolean methodName(String value)
称为someInstance::methodName
Role.isInRealm()
返回一个谓词,因此它本身不能用作谓词,因为它具有Predicate<String> methodName()
作为其签名和返回类型。 所以Role::isInRealm
不能工作。
同样r -> Role.isInRealm()
将不起作用,因为这是Function<String, Predicate<String>>
形式的 lambda(或者可能更正确: Function<?, Predicate<String>>
因为没有什么可推断r
的类型),而不是Predicate<String>
如果你想使用isInRealm
作为谓词本身,那么你需要把它写成:
public static boolean isInRealm(String role) {
return Arrays.stream(values()).anyMatch(value -> value.value.equals(role));
}
请注意,它现在返回一个布尔结果,而不是返回一个 lambda。
然后你可以使用以下方法调用它:
validateUser(Role::isInRealm);
// notice how it passes r to isInRealm
validateUser(r -> Role.isInRealm(r));
方法引用基本上是 lambda,您需要将某些东西传递给 lambda 才能使其工作,因此您的方法需要接受一个参数,并且需要有一个它消耗的值
(String s) -> System.out.println(s)
这里的 println 方法接受一个参数,你传递给它一个实际值,所以你可以在这里使用方法引用
System.out::println
但在您的情况下,我认为最好将谓词保存在变量中而不是从方法中返回它
public static Predicate<String> isInRealm = role -> Arrays.stream(values()).anyMatch(value -> value.name().equals(role));
然后你可以像这样调用validate方法
validateUser(Role.isInRealm)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.