分类器和下游和只使用分类器有什么区别

What's the difference between classifier and downstream and only using classifier

我是 Java 8 和流收集器的新手,试图了解两者之间的基本区别是什么?

因为两个代码产生相同的结果。一个使用 return groupingBy(classifier, toList()); 和 return groupingBy(classifier, HashMap::new, downstream);

这是代码

public class Grouping {
    enum CaloricLevel { DIET, NORMAL, FAT };

    public static void main(String[] args) {
        System.out.println("Dishes grouped by type: " + groupDishesByType());
        System.out.println("Dish names grouped by type: " + groupDishNamesByType());
    }


    private static Map<Type, List<Dish>> groupDishesByType() {
        return Dish.menu.stream().collect(groupingBy(Dish::getType));
    }

    private static Map<Type, List<String>> groupDishNamesByType() {
        return Dish.menu.stream().collect(groupingBy(Dish::getType, mapping(Dish::getName, toList())));
    }
}

输出:

Dishes grouped by type: {MEAT=[pork, beef, chicken], OTHER=[french fries, rice, season fruit, pizza], FISH=[prawns, salmon]}
Dish names grouped by type: {MEAT=[pork, beef, chicken], OTHER=[french fries, rice, season fruit, pizza], FISH=[prawns, salmon]}

Dish.java

public class Dish {

    private final String name;
    private final boolean vegetarian;
    private final int calories;
    private final Type type;

    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }

    public enum Type {
        MEAT, FISH, OTHER
    }

    @Override
    public String toString() {
        return name;
    }

    public static final List<Dish> menu = asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT), 
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER), 
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER), 
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("prawns", false, 400, Dish.Type.FISH), 
            new Dish("salmon", false, 450, Dish.Type.FISH));

    public static final Map<String, List<String>> dishTags = new HashMap<>();

    static {
        dishTags.put("pork", asList("greasy", "salty"));
        dishTags.put("beef", asList("salty", "roasted"));
        dishTags.put("chicken", asList("fried", "crisp"));
        dishTags.put("french fries", asList("greasy", "fried"));
        dishTags.put("rice", asList("light", "natural"));
        dishTags.put("season fruit", asList("fresh", "natural"));
        dishTags.put("pizza", asList("tasty", "salty"));
        dishTags.put("prawns", asList("tasty", "roasted"));
        dishTags.put("salmon", asList("delicious", "fresh"));
    }
}

如果这是问题

Because both the code yeild the same results. One uses return groupingBy(classifier, toList()); and return groupingBy(classifier, HashMap::new, downstream); ?

groupingBy(函数分类器,收集器下游)

There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned.

groupingBy(功能分类器, Supplier mapFactory, 收集器下游)

The Map produced by the Collector is created with the supplied factory function.

唯一的区别是,当您将 groupingBymapFactory 一起使用时,创建的 Map 是基于您的供应商逻辑(可能是自定义的、不可变的、同步的等)

what's the basic difference between the two?

主要区别在于您在完成[=32]之前的中间步骤中完成的映射 =] 收藏家。不过,您使用它们的不同方式是 groupingBy.

的签名

虽然 一方面 ,但您已将 mapperdownstream 统称为:

.collect(Collectors.groupingBy(Dish::getType,  // classifier
             Collectors.mapping(Dish::getName,  // mapper <<<< difference here
                 Collectors.toList()))) // downstream

另一方面,deault implementation of groupingBy用于

.collect(Collectors.groupingBy(Dish::getType)) 

可以扩展为类似于以下格式的格式:

.collect(Collectors.groupingBy(Dish::getType, // classifier
             Collectors.mapping(Function.identity(),  // mapper
                 Collectors.toList()))); // downstream

在你的两个例子中

.collect(groupingBy(Dish::getType));
.collect(groupingBy(Dish::getType, mapping(Dish::getName, toList())));

return 值相同,因为您的 toString() 方法仅在 Dish class return name 中。尝试向 toString() 方法添加更多信息,您会看到不同之处。

一般来说,仅使用 classifier 的 groupingBy 允许对对象进行分组,就像在您的第一个示例中一样。但是将 goupingBy 与 classifier 和下游一起使用可以让您分组的不仅仅是您的对象。例如,您可以按类型平均卡路里分组:

.collect(groupingBy(Dish::getType, averagingInt(Dish::getCalories));  // Map<Type, Double>

或找到每种类型热量最高的菜

.collect(groupingBy(Dish::getType, maxBy(Comparator.comparingInt(Dish::getCalories)));  // Map<Type, Optional<Dish>>

通常 groupingBy 本身用作双分组的下游(按类型,如果是素食则按):

.collect(groupingBy(Dish::getType, groupingBy(Dish::isVegetarian)); // Map<Type, Map<Boolean, List<Dish>>>