这个在 java 8 中使用 Optionals 的例子是否正确?你会如何重写它?
Is this example of use Optionals in java 8 correct? How would you rewrite it?
我已经开始使用 Java 的 8 个选项。我想分享这个方法,它是 "code smells" 示例,我想使用 java 8 和 optionlas 和函数式(声明式)风格重写它,所以我很想知道你对此的看法.让我们考虑一下这个方法:
public boolean isTokenValid(String userAgent, Optional<String> apiKey) {
LOGGER.info(String.format("userAgent : %s, Key ?: %s", userAgent, apiKey.isPresent()));
if ("ALFA".equalsIgnoreCase(userAgent)){
return (apiKey != null && apiKey.isPresent()
&& ispropertyExists(ALFA_TYPE, apiKey.get()));
}
else {
return (apiKey != null && apiKey.isPresent()
&& ispropertyExists(BETA_TYPE, apiKey.get()));
}
}
其中 "ispropertyExists" returns 布尔类型,"ALFA_TYPE" 和 "OMEGA_TYPE" 是枚举常量。
所以下面是我重写这个方法的方式,目的是提高可读性和实践函数式思维方式。我已经添加了评论,以解释我这样做的想法和原因,如果您认为可以改进,我很感谢您的意见和示例。
/**
* We should not pass Optionals as a parameters to the methods. We
* should use Optionals only for return value when we are not sure if value will
* be presented at the end of the calculations or not.
*/
public boolean isTokenValid(String userAgent, String apiKey) {
LOGGER.info(String.format("userAgent : %s, Key ?: %s", userAgent, apiKey));
/**
* If apiKey is null then it is incorrect. And execution will stop after
* Optional.ofNullable(apiKey), since monad will be having null value. If apiKey
* is not null then we still want to filter out empty strings. If after filter
* there will be no value, then execution will stop.
* If we have some value for apiKey then it is ok and we map the monad to the
* userAgent value to proceed the chain of calls on monad.
*/
Optional<String> userAgentOptional = Optional.ofNullable(apiKey).filter(StringUtils::isNotBlank)
.map(ak -> userAgent);
/**
* We map "userAgent" value to boolean (if it is a alfa or not). Then
* we map that boolean to boolean value which represents security check in db
* itself.
*/
Optional<Boolean> isValid = userAgentOptional.map(ua -> "ALFA".equalsIgnoreCase(ua))
.map(isAlfa -> isAlfa ? ispropertyExists(ALFA_TYPE, apiKey)
: ispropertyExists(BETA_TYPE, apiKey));
/**
* And all in all we get value from our optional boolean. If "somehow" it is
* ended up to be empty, then we retrun "false", if it is not empty, then the
* value will itself be returned.
*/
return isValid.orElse(false);
}
谢谢。
如果你喜欢函数式风格,首先尽量不要使用 null
,或者至少不要传递 null
。
但是如果你必须使用 null
,这里是我的代码:
public boolean isTokenValid(String userAgent, String apiKey) {
final Enum type = "ALFA".equalsIgnoreCase(userAgent) ? ALFA_TYPE : BETA_TYPE;
return
Optional.ofNullable(apiKey)
.filter(ak -> ispropertyExists(type, ak))
.isPresent();
}
PS:函数式风格并不意味着尝试将所有内容链接起来并避免使用临时值。相反,它是关于 纯函数 和 不可变数据 的使用。无论风格如何,我们的目标都是编写可读且合理的代码。纯函数和不可变数据非常适合这个目标。
恕我直言,你做得太过分了,也太复杂了。我同意通常我们不应该将 Optional
作为参数传递给方法。如果您不能要求传递的 apiKey
为非空,我的建议是:
public boolean isTokenValid(String userAgent, String apiKey) {
LOGGER.info(String.format("userAgent : %s, Key : %s", userAgent, apiKey));
if (apiKey == null || apiKey.isEmpty()) {
return false;
}
return ispropertyExists(
userAgent.equalsIgnoreCase("ALFA") ? ALFA_TYPE : BETA_TYPE, apiKey);
}
我会发现这非常简单。您的情况无需使用 Optional
。
我会将所有操作组合在一个链式语句中,return 避免不必要的 Optional
变量。
return Optional.ofNullable(apiKey)
.filter(StringUtils::isNotBlank)
.map(ak -> userAgent)
.map("ALFA"::equalsIgnoreCase)
.map(isAlfa -> isAlfa ? ALFA_TYPE : BETA_TYPE)
.map(type -> ispropertyExists(type, apiKey))
.orElse(false);
我已经开始使用 Java 的 8 个选项。我想分享这个方法,它是 "code smells" 示例,我想使用 java 8 和 optionlas 和函数式(声明式)风格重写它,所以我很想知道你对此的看法.让我们考虑一下这个方法:
public boolean isTokenValid(String userAgent, Optional<String> apiKey) {
LOGGER.info(String.format("userAgent : %s, Key ?: %s", userAgent, apiKey.isPresent()));
if ("ALFA".equalsIgnoreCase(userAgent)){
return (apiKey != null && apiKey.isPresent()
&& ispropertyExists(ALFA_TYPE, apiKey.get()));
}
else {
return (apiKey != null && apiKey.isPresent()
&& ispropertyExists(BETA_TYPE, apiKey.get()));
}
}
其中 "ispropertyExists" returns 布尔类型,"ALFA_TYPE" 和 "OMEGA_TYPE" 是枚举常量。 所以下面是我重写这个方法的方式,目的是提高可读性和实践函数式思维方式。我已经添加了评论,以解释我这样做的想法和原因,如果您认为可以改进,我很感谢您的意见和示例。
/**
* We should not pass Optionals as a parameters to the methods. We
* should use Optionals only for return value when we are not sure if value will
* be presented at the end of the calculations or not.
*/
public boolean isTokenValid(String userAgent, String apiKey) {
LOGGER.info(String.format("userAgent : %s, Key ?: %s", userAgent, apiKey));
/**
* If apiKey is null then it is incorrect. And execution will stop after
* Optional.ofNullable(apiKey), since monad will be having null value. If apiKey
* is not null then we still want to filter out empty strings. If after filter
* there will be no value, then execution will stop.
* If we have some value for apiKey then it is ok and we map the monad to the
* userAgent value to proceed the chain of calls on monad.
*/
Optional<String> userAgentOptional = Optional.ofNullable(apiKey).filter(StringUtils::isNotBlank)
.map(ak -> userAgent);
/**
* We map "userAgent" value to boolean (if it is a alfa or not). Then
* we map that boolean to boolean value which represents security check in db
* itself.
*/
Optional<Boolean> isValid = userAgentOptional.map(ua -> "ALFA".equalsIgnoreCase(ua))
.map(isAlfa -> isAlfa ? ispropertyExists(ALFA_TYPE, apiKey)
: ispropertyExists(BETA_TYPE, apiKey));
/**
* And all in all we get value from our optional boolean. If "somehow" it is
* ended up to be empty, then we retrun "false", if it is not empty, then the
* value will itself be returned.
*/
return isValid.orElse(false);
}
谢谢。
如果你喜欢函数式风格,首先尽量不要使用 null
,或者至少不要传递 null
。
但是如果你必须使用 null
,这里是我的代码:
public boolean isTokenValid(String userAgent, String apiKey) {
final Enum type = "ALFA".equalsIgnoreCase(userAgent) ? ALFA_TYPE : BETA_TYPE;
return
Optional.ofNullable(apiKey)
.filter(ak -> ispropertyExists(type, ak))
.isPresent();
}
PS:函数式风格并不意味着尝试将所有内容链接起来并避免使用临时值。相反,它是关于 纯函数 和 不可变数据 的使用。无论风格如何,我们的目标都是编写可读且合理的代码。纯函数和不可变数据非常适合这个目标。
恕我直言,你做得太过分了,也太复杂了。我同意通常我们不应该将 Optional
作为参数传递给方法。如果您不能要求传递的 apiKey
为非空,我的建议是:
public boolean isTokenValid(String userAgent, String apiKey) {
LOGGER.info(String.format("userAgent : %s, Key : %s", userAgent, apiKey));
if (apiKey == null || apiKey.isEmpty()) {
return false;
}
return ispropertyExists(
userAgent.equalsIgnoreCase("ALFA") ? ALFA_TYPE : BETA_TYPE, apiKey);
}
我会发现这非常简单。您的情况无需使用 Optional
。
我会将所有操作组合在一个链式语句中,return 避免不必要的 Optional
变量。
return Optional.ofNullable(apiKey)
.filter(StringUtils::isNotBlank)
.map(ak -> userAgent)
.map("ALFA"::equalsIgnoreCase)
.map(isAlfa -> isAlfa ? ALFA_TYPE : BETA_TYPE)
.map(type -> ispropertyExists(type, apiKey))
.orElse(false);