Java 空校验&;iPresent-名称不同但问题相同?
我有以下Java代码:Java 空校验&;iPresent-名称不同但问题相同?,java,nullpointerexception,return-value,optional,Java,Nullpointerexception,Return Value,Optional,我有以下Java代码: public class Browser { public URL back() { try { //simulate: fetch last URL from Stack return Math.random() < 0.5 ? new URL("http://google.de") : null; } catch(MalformedURLException e) { return null; }
public class Browser {
public URL back() {
try {
//simulate: fetch last URL from Stack
return Math.random() < 0.5 ? new URL("http://google.de") : null;
} catch(MalformedURLException e) {
return null;
}
}
public void retrieveSite(URL url) {
System.out.println(url);
//...
}
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
URL back = browser.back();
if (back != null) browser.retrieveSite(back);
}
}
现在,为了避免将空的可选
传递到检索站点
,我必须检查当前值。但是,我从检查中得到的究竟是什么呢=空值
?我是否应该返回一个默认值
,这样我就可以摆脱isPresent
我还必须更改retrieveSite()
的参数,以采用可选的
,这被认为是不好的做法
提前感谢。第二种方法的一个稍微不同的变体可以以更简洁的方式实现,如下所示:
static class Browser {
// good practice to return Optional instead of a null
Optional<URL> back() {
try {
//simulate: fetch last URL from Stack
return Math.random() < 0.5 ? Optional.of(new URL("http://google.de")) : Optional.empty();
} catch (MalformedURLException e) {
return Optional.empty();
}
}
// avoid using Optional as a parameter to a method
static void retrieveSite(URL url) {
System.out.println(url);
}
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
// perform a void operation if the URL is present (consuming it)
browser.back().ifPresent(Browser::retrieveSite);
}
}
静态类浏览器{
//返回可选值而不是空值的良好实践
可选的back(){
试一试{
//模拟:从堆栈中获取最后一个URL
返回Math.random()<0.5?可选。of(新URL(“http://google.de“”):可选。空();
}捕获(格式错误){
返回可选的.empty();
}
}
//避免将Optional用作方法的参数
静态无效检索站点(URL){
System.out.println(url);
}
公共静态void main(字符串[]args){
System.out.println(“正常背面”);
浏览器=新浏览器();
//如果存在URL,则执行作废操作(使用该URL)
browser.back().ifPresent(browser::retrieveSite);
}
}
使用可选
时,您必须打开/测试可选
以获取它,如果可选
未正确使用(快速失效原则),您还将获得早期空性异常。例如:
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
// unwraping the optional or testing it is mandatory to get the object inside in
browser.back().ifPresent(browser::retrieveSite);
// for example it will not compile
browser.retrieveSite(browser.back());
// of course you could cheat by invoking Optional.get() but that is a bad practice and the absence of object will be detected as soon as the invocation
browser.retrieveSite(browser.back().get());
}
public void retrieveSite(URL url) {
//...
}
如果没有Optional
,则如果客户端忘记显式检查no-null(url!=null
),则NPE是可能的。对于开发人员来说,这种检查实际上没有那么引人注目,因为方法调用是获取/映射包装对象所必需的。此外,如果url参数通过各层传递,您可以在最底层发现null
引用,这可能会使问题更复杂,难以理解和解决:
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
// No unwrapping is necessary to get the url.
// So the robustness of the code depends on the developer habits
browser.retrieveSite(browser.back());
}
public void retrieveSite(URL url) {
//...
}
关于
Optional
的要点并不是说它不需要进行必要的检查:这是因为您不能将Optional
视为URL
,因此您必须明确地处理存在(或不存在)。空URL
:您可以通过null
传递非空URL
,直到尝试取消引用它,您才发现。感谢您的澄清,Andy!:)您提到我应该避免使用Optional作为retrieveSite
的参数,我读了很多遍,认为这是一种不好的做法。但是为什么会是这种情况呢?@Clay91中对此已经没有什么解释了。可能值得注意的是(明确地)通过查看URL
的方法返回类型,您看不到它可能是null
,而Optional
的返回类型会立即显示它可能不存在。此外,isPresent()
与先前版本的“is notnull
”具有相同的含义,因为在此特定示例中,null
具有“is缺席”的含义。但是null
并不总是具有这种意义。有时,null
表示“我忘了初始化该字段”,在这种情况下,我永远不会切换到可选的
。@Holger同意第一部分。对于“有时,null表示“我忘了初始化那个字段”,在这种情况下,我永远不会切换到可选。“可选”不应用于字段。所以没有真正的争论。现在为字段检查NOTNULL当然是有意义的,但这与实际用例不同:返回某些内容的方法调用。当然,您不应该为字段使用optional。但是,当您创建一个返回字段值的方法时,如果字段可以是null
,您可以决定将该方法的返回类型设置为可选,如果该字段可以是null
,也可以不设置为可选。
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
// No unwrapping is necessary to get the url.
// So the robustness of the code depends on the developer habits
browser.retrieveSite(browser.back());
}
public void retrieveSite(URL url) {
//...
}