Сложные потоковые фильтры Java 8 And vs Or

У меня есть объект таблицы с тремя столбцами, которые я использую для фильтрации событий.

Три столбца с гипотетическими значениями:

Component Event SubEvent
    A       B       C
    A       B       D

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

return events -> save(events.stream().filter(event -> 
                 A != event.getComponent() && 
                 B != event.getEventType() && 
                 C != event.getEventSubType())
                    .collect(Collectors.toList())

Это ведет себя как «или» и отфильтровывает обе строки. т.е. если компонент == A || событие == B || subEvent == C

Я действительно хочу

IF (component == A && event == B && subEvent == C) затем отфильтровать, но сохранить все остальное.

Я изменил свой фильтр на

.filter(event -> C != event.getEventSubType())

Но тогда я рискую пропустить другие события, где subEvent == C, но значения Component и Event не соответствуют A и B.

Оцените любые другие предложения по стратегии по настройке такого сложного фильтра. Спасибо!

Осторожно: сравните String с equals ().

davidxxx 09.04.2018 19:08

@davidxxx, я считаю, что этот вопрос не о равенстве строк.

M. Prokhorov 09.04.2018 19:09

@M. Прохоров, про которого я не писал ответа. Но проблема связана с фильтром по строковым значениям. Так что их правильное сравнение будет хорошим началом.

davidxxx 09.04.2018 19:10

зачем писать хрупкий код, чтобы пропустить первую строку? Почему бы не использовать взамен skip(1)?

davidxxx 09.04.2018 19:12

@davidxxx, мы на самом деле не знаем, правда ли это, определения классов для типа Event не прилагаются. Это может быть enum. Он мог выбрать эти операторы, чтобы код выглядел яснее. Одна версия, которая была удалена при редактировании, определенно выглядела так, как будто там были перечисления.

M. Prokhorov 09.04.2018 19:14

Что вам здесь не хватает, так это теоремы ДеМоргана: !A && !B == !(A || B) и !A || !B == !(A && B). Вот почему он ведет себя как «или», ваш фильтр !A && !B && !C эквивалентен !(A || B || C).

Sean Van Gorder 09.04.2018 20:27

@ M.Prokhorov, спасибо, вы правы, на самом деле это перечисления, и я просто попытался упростить чтение кода без этих накладных расходов.

mba12 09.04.2018 21:54
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
7
149
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Так почему бы не создать фильтр, который точно соответствует сначала строке, а затем инвертирует ее в фильтре потока? Таким образом вы отклоните все события, соответствующие первой строке, например:

Predicate<Event> FIRST_ROW = event-> 
                 Object.equals(A , event.getComponent()) && 
                 Object.equals(B , event.getEventType() && 
                 Object.equals(C , event.getEventSubType();

save(events.stream()
.filter(FIRST_ROW.negate())
                    .collect(Collectors.toList())

Попробуйте как

save(events.stream().filter(event -> 
         !("A".equals(event.getComponent()) && 
         "B".equals(event.getEventType()) && 
         "C".equals(event.getEventSubType()))
            .collect(Collectors.toList())

Или, что то же самое

save(events.stream().filter(event -> 
         !"A".equals(event.getComponent()) || 
         !"B".equals(event.getEventType()) ||
         !"C".equals(event.getEventSubType())
            .collect(Collectors.toList())
Ответ принят как подходящий

Обратите внимание, что skip(1) позволяет пропустить первый элемент потока.

О вашей проблеме, вашем фактическом фильтре:

filter(event -> 
         A != event.getComponent() && 
         B != event.getEventType() && 
         C != event.getEventSubType())

означает, что в потоке хранятся только те элементы, которые соответствуют этим условиям three.

Посмотрите на эти строки:

 Component Event SubEvent
     A       B       C
     A       B       D

Условие ложно для первой строки. Таким образом, элемент не сохраняется. Но условие также ложно для второй строки, поскольку последовательность логического И истинна только в том случае, если все условия верны, а два из них не верны:

         A != event.getComponent()   --> false
         B != event.getEventType()   --> false
         C != event.getEventSubType() -->  true

Так что ни одна из этих строк не сохраняется.

Вы должны написать:

filter(event -> 
         !(A == event.getComponent() && 
           B == event.getEventType() && 
           C == event.getEventSubType()))
!(A == event.getComponent() && B == event.getEventType() && C == event.getEventSubType()) такой же, как A != event.getComponent() || B != event.getEventType() || C != event.getEventSubType()
Holger 09.04.2018 23:14

@Holger Конечно, я не знаю почему, но я считаю, что первый способ более читабельный.

davidxxx 10.04.2018 08:20

Другие вопросы по теме