Null-Check & isPresent - 名称不同但问题相同?
Null-Check & isPresent - Different name but same issue?
我在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 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);
}
}
我想了解有关 Optional
的更多信息并重新编写此代码,以便不再需要 return null
和 if (back!=null)
。
这就是我得到的:
public class Browser {
Optional<URL> url = Optional.empty();
public Optional<URL> back() {
try {
//simulate: fetch last URL from Stack
if(Math.random()<0.5) {
url = Optional.of(new URL("http://google.de"));
}
return url;
} catch(MalformedURLException e) {
return url;
}
}
public void retrieveSite(Optional<URL> url) {
System.out.println(url);
//...
}
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
Optional<URL> back = browser.back();
if(back.isPresent()) {
browser.retrieveSite(back);
}
}
}
现在为了避免将空 Optional
传递给 retrieveSite
,我必须检查现值。但是我从检查 isPresent
而不仅仅是 !=null
中到底得到了什么?我应该 return 一个 default
值,这样我就可以摆脱 isPresent
吗?
我还必须更改 retrieveSite()
的参数以采用 Optional
这被认为是不好的做法?
提前致谢。
第二种方法略有不同的变体可以以更简洁的方式实现:
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);
}
}
使用 Optional
你必须 unwrap/test 到 Optional
才能得到它,如果 Optional
没有被正确使用,你也会得到早期的空值异常(快速失败原则) .
例如:
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 nullity (url != null
),则可能会出现 NPE。对于 get/map 包装对象所必需的方法调用,此检查对于开发人员来说确实不那么引人注目。此外,如果 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) {
//...
}
我在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 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);
}
}
我想了解有关 Optional
的更多信息并重新编写此代码,以便不再需要 return null
和 if (back!=null)
。
这就是我得到的:
public class Browser {
Optional<URL> url = Optional.empty();
public Optional<URL> back() {
try {
//simulate: fetch last URL from Stack
if(Math.random()<0.5) {
url = Optional.of(new URL("http://google.de"));
}
return url;
} catch(MalformedURLException e) {
return url;
}
}
public void retrieveSite(Optional<URL> url) {
System.out.println(url);
//...
}
public static void main(String[] args) {
System.out.println("Normal back");
Browser browser = new Browser();
Optional<URL> back = browser.back();
if(back.isPresent()) {
browser.retrieveSite(back);
}
}
}
现在为了避免将空 Optional
传递给 retrieveSite
,我必须检查现值。但是我从检查 isPresent
而不仅仅是 !=null
中到底得到了什么?我应该 return 一个 default
值,这样我就可以摆脱 isPresent
吗?
我还必须更改 retrieveSite()
的参数以采用 Optional
这被认为是不好的做法?
提前致谢。
第二种方法略有不同的变体可以以更简洁的方式实现:
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);
}
}
使用 Optional
你必须 unwrap/test 到 Optional
才能得到它,如果 Optional
没有被正确使用,你也会得到早期的空值异常(快速失败原则) .
例如:
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 nullity (url != null
),则可能会出现 NPE。对于 get/map 包装对象所必需的方法调用,此检查对于开发人员来说确实不那么引人注目。此外,如果 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) {
//...
}