Извлечение нескольких полей из объекта в Java - PullRequest
0 голосов
/ 02 марта 2019

Этот вопрос похож на Чтение нескольких переменных из объекта, заключенного в Option [] , но в контексте Java вместо Scala.

Предположим, у меня есть метод, который возвращает Optional<Address>.Мне нужно извлечь несколько полей из упакованного адреса, скажем, getCity(), getCountry() и getZIP().Если адрес отсутствует, следует использовать некоторые значения по умолчанию.Затем следует продолжить логику с результирующими значениями.

Вопрос в том, что является лучшим и наиболее идиоматическим способом сделать это.Я могу вспомнить следующие три:

1) if-else

City city;
Country country;
ZIP zip;
Optional<Address> optAddr = getAddress();
if (optAddr.isPresent()) {
  Address addr = optAddr.get();
  city    = addr.getCity();
  country = addr.getCountry();
  zip     = addr.getZIP();
}
else {
  city    = null;
  country = Country.getUSA();
  zip     = ZIP.DEFAULT;
}
// ... use city, country, and zip

Плюсы:

  • Не создано никаких дополнительных объектов - наиболее эффективный вариант.
  • Случаи по умолчанию сгруппированы вместе.

Минусы:

  • Подробно.

2) Несколько цепочек

Optional<Address> optAddr = getAddress();
City city       = optAddr.map(Address::getCity()
                         .orElse(null);
Country country = optAddr.map(Address::getCountry)
                         .orElseGet(Country::getUSA);
ZIP zip         = optAddr.map(Address::getZIP)
                         .orElse(ZIP.DEFAULT);
// ... use city, country, and zip

Обратите внимание, что здесь логика немного отличается, поскольку значение по умолчанию применяется не только при отсутствии адреса, нотакже когда соответствующее поле адреса равно null.

Но в моем случае это не проблема.

Плюсы:

  • Краткий.
  • Переменные немедленно инициализируются значением.
  • Ближе к тому, как это делается с одним полем.

Минусы:

  • Значения по умолчанию разбиты на части.
  • Цепные вызовы map потенциально могут создавать промежуточные объекты (но идиоматическим образом).
  • Возможно, однотипное использование нескольких цепочеконет Optional?

3a) Перенос значений по умолчанию в объекте

private Address createDefaultAddress() {
  Address addr = new Address();
  addr.setCity(null);
  addr.setCountry(Country.getUSA());
  addr.setZIP(ZIP.DEFAULT);
  return addr;
}

Address addr = getAddress().orElseGet(this::createDefaultAddress);
City city       = addr.getCity();
Country country = addr.getCountry();
ZIP zip         = addr.getZIP();
// ... use city, country, and zip

Плюсы:

  • Ясность.

Минусы:

  • Поля упакованы в Address только для извлечения их сразу после этого.

3b) Обернуть значения по умолчанию в константу

Как предложено @HariMenon и @flakes, an Address со значениями по умолчанию можно сохранить в константеи повторно используется для каждого вызова, чтобы уменьшить накладные расходы.

Можно также инициализировать эту «константу» лениво:

private Address defaultAddress;

private Address getDefaultAddress() {
  if (defaultAddress == null) {
    defaultAddress = new Address();
    defaultAddress.setCity(null);
    defaultAddress.setCountry(Country.getUSA());
    defaultAddress.setZIP(ZIP.DEFAULT);
  }
  return defaultAddress;
}

Address addr = getAddress().orElseGet(this::getDefaultAddress);
// ... same as 3.1

Бонусный вопрос:

Предположим, у меня есть полный контроль над методом getAddress(), и я знаю, что все случаи использования будут аналогичны этому примеру, но значения по умолчанию различаются.Должен ли я изменить его, чтобы он возвращал null вместо Optional, чтобы лучше приспособить решение if-else?

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Я согласен с замечаниями @HariMenon.На твоем месте я бы выбрал третий вариант.Однако вместо создания нового Address каждый раз, просто создайте значения один раз и сохраните Адрес в закрытом поле.Если подходящего ctor не существует, вы можете использовать двойную инициализацию, чтобы немного упростить конструкцию.Только убедитесь, что не изменяете переменную Address по умолчанию.

private static final Address DEFAULT_ADDRESS = new Address() {{
    setCity(null);
    setCountry(Country.getUSA());
    setZIP(ZIP.DEFAULT);
}};
...
Address addr = getAddress().orElse(DEFAULT_ADDRESS);
0 голосов
/ 02 марта 2019

Это несколько субъективно, поэтому правильного ответа не будет.Но вот мои 2 цента и почему я так думаю.Вариант 1 определенно не является идиоматическим способом сделать это с Java 8.

Между 2 и 3, что вы выберете, будет зависеть от того, хотите ли вы использовать адрес по умолчанию или вы хотите отдельный город по умолчанию, страна и почтовый индекс.Если Адрес не является нулевым, но город является нулевым, вы все еще хотите использовать город по умолчанию?Вариант 3 сделает это безобразным.В противном случае я предпочитаю вариант 3. Даже если вы оберните его в объект, этот объект может быть константой с именем DEFAULT_ADDRESS, и тогда он станет совершенно ясно, что это такое, и поэтому будет более читабельным.

Опция2 заставляет его читать так, как будто у вас есть отдельная страна по умолчанию, город и почтовый индекс, что, похоже, не так.Но, как я уже сказал, если это так, вы должны использовать это.

Редактировать для 3b и бонуса : Если вы думаете о влиянии перфорирования обертки, вы слишком продуманны,Создание таких оболочек в Java чрезвычайно дешево, и современные JIT-компиляторы в большинстве случаев очень хорошо это оптимизируют.Читаемость выше перф, если код не подтвержден измерениями как узкое место перфорацииДля Optional vs null просто выберите один стиль кодирования и придерживайтесь его для проекта.

Если вы возвращаете Optionals, убедитесь, что метод никогда не возвращает null (метод, который может возвращать как Optional, так и null, являетсямерзость).Многие считают, что вы всегда должны использовать Optional s.Лично я немного не согласен.Если это новая кодовая база и мы везде используем Optionals, то это здорово.Придерживайтесь этого и нигде не используйте нулевые и нулевые проверки.Если это старая кодовая база, которая уже использует нули в нескольких местах, просто используйте нули и документируйте, что метод может возвращать ноль в некоторых случаях.Комбинация Optionals и NULL создает ужасный беспорядок, и я не думаю, что Optional дает достаточную выгоду, чтобы перевесить эту стоимость.Опционы отлично подходят для языков, которые поддерживали их с самого начала.Но они были добавлены как запоздалая мысль в Java, и у Java все еще есть нулевые значения, поэтому преимущества на самом деле не так уж велики для ИМО.Это опять же очень субъективно, и то, что я буду использовать, будет зависеть от конкретного случая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...