Java 什么';s分类器和下游之间的差异,并且仅使用分类器

Java 什么';s分类器和下游之间的差异,并且仅使用分类器,java,java-8,java-stream,collectors,Java,Java 8,Java Stream,Collectors,我对Java8和streams收集器还不太熟悉,他们试图了解两者之间的基本区别是什么 因为两个代码的结果相同。一种是使用returngroupingby(分类器,toList())并返回groupingBy(分类器,HashMap::new,down) 这是密码 public class Grouping { enum CaloricLevel { DIET, NORMAL, FAT }; public static void main(String[] args) {

我对Java8和streams收集器还不太熟悉,他们试图了解两者之间的基本区别是什么

因为两个代码的结果相同。一种是使用
returngroupingby(分类器,toList())并返回groupingBy(分类器,HashMap::new,down)

这是密码

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())));
    }
}
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"));
    }
}
公共类菜肴{
私有最终字符串名;
私人素食者;
个人最终热量;
私有最终类型;
公共菜肴(字符串名称、布尔素食、整数卡路里、类型){
this.name=名称;
这个。素食者=素食者;
这个。卡路里=卡路里;
this.type=type;
}
公共字符串getName(){
返回名称;
}
公共布尔值是素食者(){
返回素食者;
}
public int getCalories(){
返回热量;
}
公共类型getType(){
返回类型;
}
公共枚举类型{
肉、鱼、其他
}
@凌驾
公共字符串toString(){
返回名称;
}
公共静态最终列表菜单=asList(
新菜(“猪肉”,假,800,菜型,肉),
新菜(“牛肉”,假,700,菜型,肉),
新菜(“鸡肉”,假,400,菜型,肉),
新菜(“炸薯条”,真的,530,菜型,其他),
新菜(“米饭”,真的,350,菜型,其他),
新菜(“时令水果”,真的,120,菜型,其他),
新菜(“披萨”,真的,550,菜型,其他),
新菜(“虾”,假,400,菜型,鱼),
新菜(“鲑鱼”,假,450,菜型,鱼”);
public static final Map dishTags=new HashMap();
静止的{
洗碗标签。放入(“猪肉”,如“油腻”、“咸”);
盘子标签。放入(“牛肉”,如列表(“咸的”,“烤的”);
盘子标签。放入(“鸡肉”、“油炸”、“酥脆”);
餐具标签。放入(“法式炸薯条”,asList(“油腻的”,“油炸的”);
餐具标签。放入(“大米”,asList(“清淡的”,“天然的”);
放置(“时令水果”,如列表(“新鲜”、“天然”);
盘子标签。放入(“比萨饼”,如列表(“美味”、“咸”);
盘子标签。放入(“大虾”,“美味”,“烤”);
盘子标签。放入(“鲑鱼”,“美味”,“新鲜”);
}
}

如果这是个问题

因为两个代码的结果相同。一种使用returngroupingby(分类器,toList());并返回groupby(分类器,HashMap::new,down)

分组依据(函数分类器、收集器下游)

对于返回的映射的类型、可变性、序列化性或线程安全性没有任何保证

分组依据(功能分类器、供应商映射工厂、, 收集器(下游)

收集器生成的映射是使用提供的factory函数创建的

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

两者的基本区别是什么

主要区别是在完成收集器之前的中间步骤中所做的映射。不过,您使用它们的不同方式是
groupingBy
的签名

一方面,您将
映射器
下游
统称为:

.collect(Collectors.groupingBy(Dish::getType,  // classifier
             Collectors.mapping(Dish::getName,  // mapper <<<< difference here
                 Collectors.toList()))) // downstream
可扩展为类似以下格式:

.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())));
返回值相同,因为您的
toString()
方法仅在
Dish
类中返回
name
。尝试向
toString()
method添加更多信息,您将看到不同之处

通常,使用仅带有分类器的
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>>

您的代码示例与讨论中的示例不同<代码>收集器。映射
vs
groupingBy(分类器,HashMap::新建,下游)
。你真正的问题是什么?
.collect(groupingBy(Dish::getType, averagingInt(Dish::getCalories));  // Map<Type, Double>
.collect(groupingBy(Dish::getType, maxBy(Comparator.comparingInt(Dish::getCalories)));  // Map<Type, Optional<Dish>>
.collect(groupingBy(Dish::getType, groupingBy(Dish::isVegetarian)); // Map<Type, Map<Boolean, List<Dish>>>