分类器和下游并且仅使用分类器有什么区别

时间:2019-02-03 16:55:44

标签: java java-8 java-stream collectors

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

因为两个代码均获得相同的结果。一个使用return groupingBy(classifier, toList());并返回groupingBy(classifier,HashMap :: new,下游);

这是代码

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"));
    }
}

3 个答案:

答案 0 :(得分:1)

如果这是问题

  

因为两个代码均获得相同的结果。一种使用return groupingBy(classifier,toList());并返回groupingBy(classifier,HashMap :: new,下游); ?

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

  

无法保证返回的Map的类型,可变性,可序列化性或线程安全性。

groupingBy(功能分类器,供应商mapFactory, 下游收集器)

  

使用提供的工厂功能创建收集器生成的地图。

唯一的区别是,当您将$data = [ [ 'id' => 1, 'parent_id' => '0', 'name' => 'A', ], [ 'id' => 2, 'parent_id' => '1', 'name' => 'A > B', ], [ 'id' => 3, 'parent_id' => '2', 'name' => 'A > B > C', ] ]; $names = array_column($data,'name','id'); print_r($names); //[1 => 'A', 2 => 'A > B', 3 => 'A > B > C'] groupingBy一起使用时,mapFactory的创建是基于您的供应商逻辑(可能是自定义的,不可变的,同步的等等)。

答案 1 :(得分:0)

  

两者之间的基本区别是什么?

主要区别是您在完成收集器之前的中间步骤中完成的 映射 。不过,您使用它们的不同方式是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

答案 2 :(得分:0)

在您的两个示例中

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

返回值相同,因为您的toString()类中的Dish方法仅返回name。尝试将更多信息添加到toString()方法中,您会发现有所不同。

通常,仅在分类器上使用groupingBy可以对对象进行分组,就像您的第一个示例一样。但是,将goupingBy与分类器和下游一起使用,可以使您分组的数量远远超过仅对象。例如,您可以按类型将平均卡路里分组

.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>>>