I have the following code in 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);
}
}
I want to learn more about Optional
and re-write this code so that return null
and if (back!=null)
is not required anymore.
So this is what i got:
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);
}
}
}
Now in order to avoid passing an empty Optional
to retrieveSite
, i have to check for a present value. But what exactly am I gaining from checking for isPresent
instead of just !=null
? Should i return a default
value instead, so i can get rid of isPresent
?
Also i had to change the Parameter for retrieveSite()
to take an Optional
which is considered as bad practice?
Thanks in advance.
With Optional
you have to unwrap/test the Optional
to get it and you also get early emptiness exception if Optional
is not correctly used (fail fast principle).
For example :
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) {
//...
}
Without Optional
, a NPE is possible if the client forget to check explicitly the no nullity (url != null
). This check is really less compelling for the developper that a method invocation that is mandatory to get/map the wrapped object. Besides, you can discover the null
reference later in a very bottom layer if the url parameter is passed through the layers, which makes issues potentially more complicated to understand and solve :
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) {
//...
}