Тернарный оператор в Java Streams

У меня есть следующая функция, которая использует потоки и коллекторы для создания карты и отличается выполнением на основе логического входного параметра isMultiSelectableQuiz:

private Map<Integer, Long> getCountPerAnswerChoice(boolean isMultiSelectableQuiz, int questionId, List<QuizResponse> quizResponses) {
     return isMultiSelectableQuiz
        ? quizResponses.stream()
            .flatMap(response -> response.getAnswersByQuestions().stream())
            .filter(answerByQuestion -> answerByQuestion.getQuestionId() == questionId)
            .collect(
                Collectors.flatMapping(
                    (QuizQuestionAnswer answerByQuestion) -> answerByQuestion.getAnswerSelectionsList().stream(),
                    Collectors.groupingBy(selection -> selection, Collectors.counting())))
        : quizResponses.stream()
            .flatMap(response -> response.getAnswersByQuestions().stream())
            .filter(answerByQuestion -> answerByQuestion.getQuestionId() == questionId)
            .collect(
                Collectors.groupingBy(QuizQuestionAnswer::getAnswerSelection, Collectors.counting()));
    }

Есть ли способ упростить этот код и сделать его более элегантным, поскольку следующая часть повторяется в обеих ветвях if/else

quizResponses.stream()
            .flatMap(response -> response.getAnswersByQuestions().stream())
            .filter(answerByQuestion -> answerByQuestion.getQuestionId() == questionId)

Я попытался переместить проверку isMultiSelection ? : внутри collect(), но это выдает ошибку времени компиляции.

private Map<Integer, Long> getCountPerAnswerChoice(boolean isMultiSelectableQuiz, int questionId, List<QuizResponse> quizResponses) {
     return quizResponses.stream()
        .flatMap(response -> response.getAnswersByQuestions().stream())
        .filter(answerByQuestion -> answerByQuestion.getQuestionId() == questionId)
        .collect(
            isMultiSelectableQuiz
                ? Collectors.groupingBy(
                    QuizQuestionAnswer::getAnswerSelection, Collectors.counting())
                : Collectors.flatMapping(
                    (QuizQuestionAnswer answerByQuestion) -> answerByQuestion.getAnswerSelectionsList().stream(),
                    Collectors.groupingBy(selection -> selection, Collectors.counting())));
    }

Если вы переместите крючок внутри вызова collect, вы можете избавиться от первых четырех строк дублирования (от quizResponses до collect).

Dawood ibn Kareem 17.05.2022 03:28

Я пробовал это, но в сборе() no suitable method found for collect возникает ошибка компиляции.

tigh75 17.05.2022 03:30

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

Dawood ibn Kareem 17.05.2022 03:34
getAnswersByQuestions нужен () после него.
David Conrad 17.05.2022 03:54
Основы программирования на Java
Основы программирования на Java
Java - это высокоуровневый объектно-ориентированный язык программирования, основанный на классах.
Концепции JavaScript, которые вы должны знать как JS программист!
Концепции JavaScript, которые вы должны знать как JS программист!
JavaScript (Js) - это язык программирования, объединяющий HTML и CSS с одной из основных технологий Всемирной паутины. Более 97% веб-сайтов используют...
1
4
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я обнаружил, что компилятор java с трудом выводит аргументы типа, когда они передаются от потока к сборщику. Единственная разница между вашими двумя вариантами использования заключается в используемом сборщике. Я бы вынес коллекторы в отдельный метод, чтобы возвращать соответствующий коллектор для каждого случая. Это не только помогает очистить код, возвращаемый тип метода, предоставляющего сборщик, уточняет типы, избегая ошибки.

private Map<Integer, Long> getCountPerAnswerChoice(boolean isMultiSelectableQuiz,
        int questionId, List<QuizResponse> quizResponses) {
    return quizResponses.stream()
        .flatMap(response -> response.getAnswersByQuestions().stream())
        .filter(answerByQuestion -> answerByQuestion.getQuestionId() == questionId)
        .collect(getCollectorForQuizType(isMultiSelectableQuiz));
}

private Collector<? super QuizQuestionAnswer, ?, Map<Integer, Long>> getCollectorForQuizType(
        boolean isMultiSelectableQuiz) {
    return isMultiSelectableQuiz
        ? Collectors.groupingBy(QuizQuestionAnswer::getAnswerSelection, Collectors.counting())
        : Collectors.flatMapping(
            answerByQuestion -> answerByQuestion.getAnswerSelectionsList().stream(),
            Collectors.groupingBy(selection -> selection, Collectors.counting()));
}

Я бы даже подумал о том, чтобы разбить его дальше, возможно, сохранив коллекторы в полях и просто вернув их по имени. Он все еще выглядит слишком занятым для меня с троичным там. Или верните один внутри блока if, и если он провалится, верните другой.

подумайте о том, чтобы разбить его дальше — если это частая операция, рекомендуется определить эти коллекторы как статические поля, другой вариант — обернуть каждый из них методом. Что-то вроде return isMultiSelectableQuiz ? group() : flattenAndGroup();
Alexander Ivanchenko 17.05.2022 12:46

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

Похожие вопросы

Как бы я отформатировал свой двоичный файл в 4-битных группах после моей программы преобразования двоичных файлов в Java?
Контроллер Autowired в тесте Spring Boot имеет значение null
Как правильно реализовать блокирующий, потокобезопасный метод записи для сокетов Java?
Jooq Multiset — SQL показывает синтаксическую ошибку слова multiset thorwing — Postgres
Ошибка в java.lang.RuntimeException: невозможно запустить активность ComponentInfo{}: java.lang.NullPointerException
Общий секрет Java X25519 неверен при использовании тестовых векторов из RFC7748
Возможности выполнения groovy-скрипта с помощью Hybris в java-коде (без hAC)
Как установить параметр Jpa Query из MessagingGateway?
Как вычислить как можно больше простых чисел за десять секунд, используя потоки в java
Класс X не может быть приведен к классу Boolean (X находится в безымянном модуле загрузчика 'app'; логическое значение находится в модуле java.base загрузчика 'bootstrap