Null-Check & isPresent - другое имя, но та же проблема? - PullRequest
2 голосов
/ 21 мая 2019

У меня есть следующий код на 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?Должен ли я вместо этого вернуть значение default, чтобы я мог избавиться от isPresent?

Также мне пришлось изменить параметр на retrieveSite(), чтобы взять Optional, что считается плохой практикой?

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Немного другой вариант для вашего второго подхода может быть реализован намного чище:

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);
    }
}
0 голосов
/ 21 мая 2019

С 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, NPE возможен, если клиент забудет явно проверить отсутствие нуля (url != null).Эта проверка действительно менее привлекательна для разработчика, чем вызов метода, который является обязательным для получения / отображения обернутого объекта.Кроме того, вы можете обнаружить ссылку null позже в самом нижнем слое, если параметр url передан через слои, что делает проблемы потенциально более сложными для понимания и решения:

  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) {        
    //...
  }
...