假设我不知道一个Optional
是否为空,或两者是否存在。在后一种情况下,我总是希望a
优先于b
:
final Optional<String> a = Optional.of("1");
final Optional<String> b = Optional.empty();
if (a.isPresent() || b.isPresent()) {
// prefer a over b
Integer result = a
.map(s -> s + "0")
.map(Integer::parseInt)
.orElseGet(() -> Integer.parseInt(b.get())); // <-- warning for b.get()
System.out.println(result);
}
在我的真实代码中,Idea在此时警告我:
'Optional.get()'没有'isPresent()'检查。
为什么?如果a
或b
存在,我之前会检查。此外,此代码按预期工作,输出为10
。如果我放b = Optional.of("2")
,则输出仍为10
,因为我更喜欢a
。如果我然后放a = Optional.empty()
,则输出结果为2
。
我做错了什么,或者是Idea的错误?
答案 0 :(得分:4)
在这种情况下,看起来像IDEAs linting是错误的,但它很可能与决定b.isPresent()
后备中a.orElseGet(...)
是否得到保证的复杂性有关。 。
一般来说,我发现如果IDE警告某事,通常一个好主意(双关语)来修复它,因为下一个开发人员来看看代码也会很难解读代码背后的意图。
由于您已经在使用Optional
,我会考虑根本不使用isPresent
方法,并使用api为您完成工作。我可以看到两个应该满足警告的选项(双关语)。
如果两者都不存在,您可以提供合适的后备:
final Optional<String> a = Optional.of("1");
final Optional<String> b = Optional.empty();
// prefer a over b
Integer result = a
.map(s -> s + "0")
.map(Integer::parseInt)
.orElseGet(() -> b.map(Integer::parseInt).orElse(0));
System.out.println(result);
如果你从不期望两者都是空的,你可以抛出IllegalStateException
而不是后备:
final Optional<String> a = Optional.of("1");
final Optional<String> b = Optional.empty();
// prefer a over b
Integer result = a
.map(s -> s + "0")
.map(Integer::parseInt)
.orElseGet(() -> b.map(Integer::parseInt).orElseThrow(IllegalStateException::new));
System.out.println(result);
答案 1 :(得分:3)
这个想法在这里很混乱,它的内部规则可能会假设对相同可选链接中的isPresent
进行检查。
由于Optional
,这显然位于(a.isPresent() || b.isPresent())
检查之外;由于这些检查,无法判断无法在空的可选orElseGet
上调用b
...
答案 2 :(得分:2)
长话短说:在IDEA 2017.3中修复(见IDEA-174759)。
是的,保证b
出现在b.get()
点。是的,IDEA警告是错误的。原因是当前版本中的IDEA分析不够复杂,无法理解可选链中的内容。请注意,结果还取决于Integer::parseInt
方法引用永远不会生成null
的事实。否则Optional.map
即使a
存在,也可能产生空可选项。例如,考虑以下代码:
private static Integer myParseInt(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null;
}
}
...
if (a.isPresent() || b.isPresent()) {
// prefer a over b
Integer result = a.map(s -> s + "0").map(MyClass::myParseInt)
.orElseGet(() -> Integer.parseInt(b.get()));
System.out.println(result);
}
如果b
包含非数字字符串,则a
可能不存在,因此需要提示警告。
我们不断改进IDEA静态分析。在2017.3中,它将理解这些结构:
正如您所看到的,现在警告未显示在原始代码中,但显示为可为空myParseInt
。
IDEA 2017.3尚未推出。但是,由于此功能是IDEA社区的一部分,您可以使用主分支中的GitHub sources自行构建。
免责声明:我是IntelliJ IDEA开发人员,我正在努力解决此问题。
答案 3 :(得分:0)
您正在检查a.isPresent()和b.isPresent()in或condition。你正在收到警告,因为可能会发生条件的第一部分证明是真的&#34; a.isPresent()&#34;但是b.isPresent()是假的。但是,由于||条件块内的代码将开始执行。在这种情况下,b.get将失败,并且#34; NoSuchElementException&#34;。
虽然根据你的逻辑,如果b不存在或空,b.get()是不可达的,因为你更喜欢超过b。但IDE会分析并主动告诉您所有错误或代码中的错误做法。
尝试做类似的事情:
if(a.isPresent()){
//logic if a is there
}
else if(b.isPresent){
//logic if a not there and b is there
}
else{
logic if both are not there
}