notification-portlet-api/src/main/java/org/jasig/portlet/notice/NotificationResponse.java
private void addCategories(List<NotificationCategory> newCategories) {
        if (newCategories == null) {
            return;
        }

        // Start with a deep copy of the method parameter to simplify remaining logic
        newCategories = newCategories.parallelStream().map(NotificationCategory::cloneNoExceptions).collect(Collectors.toList());

        // Create a map of current categories by title for processing
        Map<String, NotificationCategory> catsByName =
                this.categories.parallelStream().collect(toMap(c -> c.getTitle().toLowerCase(), c -> c));

        // Split new categories between those that match an existing category and those that are completely new
        Map<Boolean, List<NotificationCategory>> matchingNewCats =
                newCategories.stream()
                        .collect(partitioningBy(c -> catsByName.containsKey(c.getTitle().toLowerCase())));

        // Add new entries to existing categories
        matchingNewCats.get(Boolean.TRUE).stream()
                .forEachOrdered(c -> catsByName.get(c.getTitle().toLowerCase()).addEntries(c.getEntries()));

        // Add new categories
        this.categories.addAll(matchingNewCats.get(Boolean.FALSE));
    }
private void addCategories(List<NotificationCategory> newCategories) {
        if (newCategories == null) {
            return;
        }

        // Start with a deep copy of the method parameter to simplify remaining logic
        newCategories = newCategories.parallelStream().map(NotificationCategory::cloneNoExceptions).collect(Collectors.toList());

        // Create a map of current categories by title for processing
        Map<String, NotificationCategory> catsByName =
                this.categories.parallelStream().collect(toMap(c -> c.getTitle().toLowerCase(), c -> c));

        // Split new categories between those that match an existing category and those that are completely new
        Map<Boolean, List<NotificationCategory>> matchingNewCats =
                newCategories.stream()
                        .collect(partitioningBy(c -> catsByName.containsKey(c.getTitle().toLowerCase())));

        // Add new entries to existing categories
        matchingNewCats.get(Boolean.TRUE).stream()
                .forEachOrdered(c -> catsByName.get(c.getTitle().toLowerCase()).addEntries(c.getEntries()));

        // Add new categories
        this.categories.addAll(matchingNewCats.get(Boolean.FALSE));
    }
Insert the given categories and their entries into the any existing
categories of the same title. If a category doesn't match an existing
one, add it to the list.
@param newCategories collection of new categories and their entries.