Null-Check&isPresent-名称不同但问题相同?

时间:2019-05-21 16:49:31

标签: 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 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 nullif (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到底能得到什么呢?我应该返回一个default值,以便摆脱isPresent吗?

我还必须更改retrieveSite()的参数以采用Optional,这被认为是不好的做法吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

第二种方法的稍有不同的变体可以更简洁的方式实现:

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);
    }
}

答案 1 :(得分:0)

使用Optional时,您必须解包/测试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 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) {        
    //...
  }