Необязательный isPresent vs orElse (null) - PullRequest
0 голосов
/ 28 августа 2018

Я обновлял зависимости до Spring 5 в моем проекте и был засыпан ошибками компиляции, когда определение метода findOne() было заменено на findById(), которое теперь возвращает Optional (исправьте меня, если я ошибаюсь) .

Во время рефакторинга я натолкнулся на несколько подходов, которые я могу выбрать, и поэтому мне хотелось бы, чтобы какой-то вклад был предпочтительным.

1-й подход:

ExpectedPackage ep = expectedPackageRepository.findById(1).orElse(null);
if(ep != null){
    ep.setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep);
}

2-й подход:

Optional<ExpectedPackage> ep = expectedPackageRepository.findById(1);
if(ep.isPresent()){
    ep.get().setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep.get());
}

Или есть третий и лучший подход, который я пропустил? Я прошел несколько вопросов и пару статей, но не нашел четкого ответа.

Ответы [ 4 ]

0 голосов
/ 28 августа 2018

Да, есть и другие подходы.

Если вы абсолютно ожидаете, что всегда будет какое-либо значение, используйте Optional::orElseThrow, чтобы выдать исключение, если появляется ноль.

Если вы ожидаете, что ноль, возможно, прибудет, и у вас есть альтернативный экземпляр, доступный как запасной вариант, используйте Optional::orElse.

Если резервный экземпляр отсутствует, но у вас есть функция, которую нужно вызвать для предоставления резервного экземпляра, используйте Optional::orElseGet.

Если вы не заботитесь о получении нулевого значения и не хотите ничего делать при получении нулевого значения, используйте Optional::ifPresent. Передайте блок кода, который будет запущен, если получит значение.

Если вас волнует только то, что приходит значение, удовлетворяющее некоторым требованиям, используйте Optional::filter. Передайте Predicate, определяющий ваши требования. Например, нам важно только, если Optional< String > содержит текст и , в этом тексте есть слово purple: myOptional.filter( s -> s.contains( "purple" ) ).ifPresent( this::print ) ;. Если получено значение null, наша желаемая операция (в данном примере вызов print) никогда не происходит. Если значение было получено, но не соответствует нашему предикату, желаемая операция никогда не происходит.


Выполнение if( myOptional.isPresent() ) { SomeClass x = myOptional.get() ; … } является действительным и безопасным. Но это не первоначальное намерение Optional, так как это в основном то же самое, что и старомодная нулевая проверка if ( null == x ) { … }. Другие методы Optional предоставляют более четкий и элегантный способ выразить свои намерения в отношении возможного появления ноля.

0 голосов
/ 28 августа 2018

Другой ответ - это, по сути, рефакторинг вашего второго подхода, который сам по себе не имеет ничего плохого, это просто вопрос стиля. Конечно, связывание и извлечение в отдельный метод сделает это намного более читабельным и понятным, без сомнения (+1 от меня), особенно с учетом правильного использования ifPresent.

Я бы просто добавил здесь, что get, ну, как-то было воспринято как ошибка проектирования (или может быть неправильным именем метода, возможно, оно пришло из guava мышления). Использование get, даже если документально подтверждено, что выдается исключение, когда это значение отсутствует, несколько странно (если вы думаете, что получатели здесь, вы не ожидаете, что getter сгенерирует исключение). И вы не ожидаете, что get нужно будет назвать после isPresent, по крайней мере, не в самых первых взаимодействиях с Optional. Таким образом, get было предложено объявить устаревшим (и, будем надеяться, удаленным), поэтому java-10 добавляет лучшее добавление orElseThrow() - это имеет смысл сразу после того, как вы его прочитаете, потому что бросающая часть находится в названии метода, поэтому нет сюрпризы.

Кроме того, кто-то должен рассказать вам об использовании new Date(), что при использовании с Optional из java-8 выглядит странно, уже есть гораздо лучшие классы, связанные с датой и временем.

Я также не очень уверен, почему вы обновляете дату изменения вручную, когда для этого есть весенние аннотации, такие как PreUpdate/PrePersist.

0 голосов
/ 28 августа 2018

Вы также можете сделать:

Optional<ExpectedPackage> updatedPackage = expectedPackageRepository.findById(1).map(ep -> {
    ep.setDateModified(new Date());
    return expectedPackageRepository.saveAndFlush(ep);
});
0 голосов
/ 28 августа 2018

Вы также можете сделать:

expectedPackageRepository.findById(1).ifPresent(
    ep -> {
        ep.setDateModified(new Date());
        expectedPackageRepository.saveAndFlush(ep);
    }
);

В идеале вы должны также извлечь часть в скобках ({}) в отдельный метод. Тогда вы могли бы написать так:

    expectedPackageRepository.findById(1).ifPresent(this::doSomethingWithEp);

Где:

void doSomethingWithEp(ExpectedPackage ep) {
    ep.setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep);
}

С документацией ifPresent можно ознакомиться здесь: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-

Как говорится, он будет выполнять указанное действие, если значение присутствует, и не будет делать ничего другого.

...