Использование Optional для предотвращения указателей NULL в TrainWrecks

#java #optional #misuse

#java #необязательно #неправильное использование

Вопрос:

Мне просто интересно, является ли следующее неправильным вариантом использования Optional. Вероятно, так и есть, потому что это выглядит неприятно.

(Речь идет о вызове «устаревшего» кода, который возвращает нули.)

   private static class Person {
    private Address address;
    private String name;
  }

  private static class Address {
    private Integer housenr;
    private String houseletter;
    private String street;
  }

  public String getAddress(Person person) {
    return Optional.ofNullable(person.getAddress())
      .map(x -> Optional.ofNullable(x.getHousenr()).map(y -> y   " ").orElse("")  
          Optional.ofNullable(x.getHouseletter()).map(y -> y   " ").orElse("")  
          Optional.ofNullable(x.getStreet()).orElse(""))
      .orElse("<unknown>");
  }

  // unit test if string representation of an address is properly generated
  assertThat(getAddress(charlesBabbage))
      .isEqualTo("4 l Regentstreet");
 

Вероятно, мне следует поместить код в метод класса Person и класса Address, чтобы меня это не так сильно беспокоило.

Или я должен сделать это «по-старому»:

   public String getAddress(Person person) {
    if (person.getAddress() == null) {
      return "<unknown>";
    }
    StringBuilder builder = new StringBuilder();
    if (person.getAddress().getHousenr() != null) {
      builder.append(person.getAddress().getHousenr()   " ");
    }
    if (person.getAddress().getHouseletter() != null) {
      builder.append(person.getAddress().getHouseletter()   " ");
    }
    if (person.getAddress().getStreet() != null) {
      builder.append(person.getAddress().getStreet()   " ");
    }
    return builder.toString();
  }

 

Имейте в виду, что это всего лишь пример. Можно добавить дополнительные поля, такие как affix., почтовый ящик, город / город, муниципалитет, штат, страна (не говоря уже об иностранных адресах), что усугубляет проблему.

Комментарии:

1. это нечитаемо, просто укажите поля по отдельности

2. Извините, @Andrew Tobliko. Прояснил цель кода.

3. оба выглядят плохо для меня, зачем вам нужно создавать строку? макет «4 l Regentstreet» в качестве объекта адреса и сравнение 2 объектов

4. Мне нужно создать строку, чтобы представить ее пользователю.

Ответ №1:

В обоих ваших примерах вы повторяете код, который проверяет, что элементы не являются нулевыми, прежде чем добавлять их в строку. Вы можете уменьшить эту повторяющуюся работу, используя Stream и joining:

 public String getAddress(Person person) {
    return Optional.ofNullable(person.getAddress())
            .map(x -> Stream.of(x.getHousenr(), x.getHouseletter(), x.getStreet())
                        .filter(Objects::nonNull)
                        .map(Object::toString)
                        .collect(Collectors.joining(" "))
            )
            .orElse("<unknown>");
}
 

Или аналогично без Optional:

 public String getAddress(Person person) {
    Address address = person.getAddress();
    if (address == null) {
        return "<unknown>";
    }
    return Stream.of(address.getHousenr(), address.getHouseletter(), address.getStreet())
            .filter(Objects::nonNull)
            .map(Object::toString)
            .collect(Collectors.joining(" "))
}
 

Ответ №2:

Я вообще не считаю, что это неправильный вариант использования. Правда, это не так просто читать, не думая о форматировании и пробелах, но способ, который вы используете Optional , кажется мне прекрасным.

Ради утверждения хорошо иметь этот (действительно уродливый) код. Я не знаю вашего окончательного предполагаемого варианта использования, но предполагая, что вы просто хотите сгенерировать строковые представления этих объектов, я бы инкапсулировал логику, которая проверяет наличие нулей в соответствующих классах, в toString() метод или аналогичный.

редактировать: неприятный вид кода не делает его использование неправильным. Хотя ваши коллеги могут в конечном итоге возненавидеть вас

Комментарии:

1. Хотя рабочий код важен, неприятный код, скорее всего, неоправданно увеличит затраты на обслуживание, и это тоже очень важно…. ЧАСТО это важнее, чем «рабочий» код; особенно если ожидаемая продолжительность жизни системы составляет годы. ВСЕГДА переосмысливайте свою стратегию, если интуиция подсказывает вам, что код уродлив или нечитаем.