[英]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.