Как сделать карту потока Java 8 непрерывно с проверкой нуля - PullRequest
0 голосов
/ 25 декабря 2018

У меня есть этот кусок кода

Coverage mainCoverage = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
    .getCoverages()  
    .stream() // <==may cause null here if list coverage is null
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

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

Я пытаюсь преобразовать этот код в

Coverage mainCoverage1 = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .map(Life::getCoverages)
    .filter(Coverage::isMainplan) //<== cannot filter from list coverage to one main coverage
    ...

Кажется, после того, как я сопоставляю жизнь с покрытием, это больше не список покрытия.Итак, вопрос в том, как я могу преобразовать первый раздел в нулевой сейф и, возможно, сократить его?

Ответы [ 5 ]

0 голосов
/ 02 апреля 2019

Пример, который вы дали, и ответы, приведенные здесь для него, нарушают некоторые принципы чистого функционального кодирования стиля.

Во-первых, вам не следует смешивать действия терминала и снова создавать потоки в той же цепочке / конвейере кода,Как и в вашем примере stream (). FindFirst (). OrElseThrow (..). Stream (). OtherActions.Это действительно не очень хорошая практика и подвержена ошибкам.В идеале цепочка вызовов API Java Stream должна работать с одним потоком.Таким образом легче следовать и рассуждать о вашем коде.

Во-вторых, вы упомянули, что этот бит может попасть в Null Pointer exc:

.getCoverages()  
.stream() // <==may cause null here if list coverage is null

, если getCoverages () должен вернуть коллекцию,он никогда не должен возвращать ноль, всегда возвращать пустую коллекцию.

Разбейте ваш код на отдельные логические части и дайте ему несколько значимых имен:

Coverage mainCoverage = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

Coverage mainplan = mainCoverage.getCoverages().stream()
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));

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

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

Вы можете попытаться инкапсулировать результирующее Collection<Coverage> в Optional<Collection<Coverage>>, чтобы можно было отображать в нулевой безопасный способ.

final Supplier<ServiceInvalidAgurmentGeneraliException> customExceptionThrower = () -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002"));

final Collection<Coverage> firstMainLifeCoverages = illus.getLifes().stream()
    .filter(Life::isIsmain)
    .findFirst()
    .orElseThrow(customExceptionThrower)
    .getCoverages();

Optional.ofNullable(firstMainLifeCoverages)
    .map(Collection::stream)
    .orElseThrow(customExceptionThrower)
    .filter(Coverage::isMainplan)
    .findFirst()
    .orElseThrow(customExceptionThrower);
0 голосов
/ 25 декабря 2018

В первой части вашего кода вы можете вставить filter(e -> e != null), чтобы убедиться, что List равно нулю, не будет выбрасывать NPE:

Coverage mainCoverage = illus.getLifes().stream()
         .filter(Life::isIsmain)
         .findFirst()
         .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
         .getCoverages()  
         .filter(e -> e != null) //<=== Filter out all null values
         .stream()
         .filter(Coverage::isMainplan)
         .findFirst()
         .orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002"))

Проблема с вашим вторымФрагмент кода: я предполагаю, что Life::getCoverages возвращает Collection, а не отдельные Coverage объекты, поэтому вы не можете вызвать Coverage::isMainplan для него

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

Добавить условие в filter, если список не нулевой и i.isIsmain, тогда только фильтр, вы можете использовать public static boolean isNull(Object obj) или public static boolean nonNull(Object obj)

Coverage mainCoverage = illus.getLifes().stream()
.filter(i->i.isIsmain && Objects.nonNull(i.getCoverages()))
.findFirst()
.orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")))
.getCoverages()  
.stream() // <==may cause null here if list coverage is null
.filter(Coverage::isMainplan)
.findFirst()
.orElseThrow(() -> new ServiceInvalidAgurmentGeneraliException(env.getProperty("MSG_002")));
0 голосов
/ 25 декабря 2018

Life::getCoverages возвращает коллекцию, следовательно, фильтр Coverage::isMainplan не будет работать, вместо этого вам следует flatMap последовательности, возвращенные после .map(Life::getCoverages), затем применить операцию filter к Coverage:

Coverage mainCoverage = 
          illus.getLifes()
               .stream()
               .filter(Life::isIsmain)               
               .map(Life::getCoverages)
               //.filter(Objects::nonNull) uncomment if there can be null lists
               .flatMap(Collection::stream) // <--- collapse the nested sequences
               //.filter(Objects::nonNull) // uncomment if there can be null Coverage
               .filter(Coverage::isMainplan)
               .findFirst().orElse(...);

Я добавил несколько вещей в ваш код:

  1. Я добавил .filter(Objects::nonNull) после .map(Life::getCoverages), которые вы можетераскомментируйте, учитывая, что возвращаемые элементы потенциально могут быть нулевыми.
  2. Я добавил .flatMap(Collection::stream), который возвращает поток, состоящий из результатов замены каждого элемента этого потока содержимым сопоставленногопоток создается путем применения предоставленной функции отображения к каждому элементу.
  3. Я добавил еще один .filter(Objects::nonNull), который вы можете раскомментировать, если элементы, возвращенные после flatMap, потенциально могут быть нулевыми.
  4. Мы тогда на стадиив котором мы можем применить .filter(Coverage::isMainplan) и, наконец, получить первый объект, удовлетворяющий критериям, через findFirst, а если его нет, указать значение по умолчанию через orElse.

Я бы предложил иметьпосмотрите следующие блоги, чтобы ознакомиться с методом flatMap:

...