Как правильно обработать Java 8 поток «findFirst ()» результат, даже если он пуст - PullRequest
0 голосов
/ 12 декабря 2018

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

Например, если у меня есть кодкак это:

String pymtRef = defaultValue;
Optional<PaymentTender> paymentTender = paymentTenders.stream()
        .filter(pt -> (pt.getFlag() == Flag.N || pt.getFlag() == null)).findFirst();
if (paymentTender.isPresent()) {
    pymtRef = paymentTender.get().getId();
}
return pymtRef;

Я хотел бы выяснить, как удалить условный блок и сделать это в одном потоке.

Если я просто вызову «.map» в результате фильтра, который может работать, если он нашел подходящую запись.Если нет, я получаю NoSuchElementException.

Я мог бы вместо этого использовать «ifPresent ()», но тип возвращаемого значения «void».

Есть ли способ сделать это чище?

Обновление :

Решение, использующее "orElse ()", работает нормально.

Весь метод теперь выглядит примерно так:

public String getPaymentReference(OrderContext orderContext) {
    List<PaymentTender> paymentTenders = getPaymentTenders(orderContext);
    if (paymentTenders.size() == 1) {
        return paymentTenders.get(0).getId();
    }
    return paymentTenders.stream()
            .filter(pt -> (pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null))
            .findFirst().map(pt -> pt.getId()).orElse(DEFAULT_VALUE);
}

Можете ли вы придумать способ включить первое условное выражение в поток, не усложняя его?

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Вы можете сделать это одним оператором через

public String getPaymentReference(OrderContext orderContext) {
    List<PaymentTender> paymentTenders = getPaymentTenders(orderContext);
    return paymentTenders.stream()
        .filter(paymentTenders.size() == 1? pt -> true:
                pt -> pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null)
        .findFirst().map(PaymentTender::getId).orElse(DEFAULT_VALUE);
}

Обратите внимание, что это не повторит оценку paymentTenders.size() == 1 для каждого элемента, но будет использовать другую функцию, в зависимости от состояния.Когда условие выполнено, pt -> true примет любой элемент, что приведет к тому, что единственный элемент будет принят как предполагалось.В противном случае используется обычный предикат pt -> pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null.

0 голосов
/ 12 декабря 2018

Вызов get() сразу после map приведет к исключению, если у Optional есть пустое состояние, вместо этого вызовите orElse после map и укажите значение по умолчанию:

paymentTenders.stream()
            .filter(pt -> (pt.getFlag() == Flag.N || pt.getFlag() == null))
            .findFirst()
            .map(PaymentTender::getId)
            .orElse(someDefaultValue);

Редактировать:

Что касается:

Можете ли вы придумать способ включить первое условие в поток, не усложняя его?

Нет, лучше так, как ты это сделал.это более читабельно и легче для понимания.

введение любого типа логики для превращения его в один конвейер (, если возможно ) просто перестанет быть сложным и, следовательно, будет труднее следовать и понимать.

...