Java 8 Streams - collect vs reduce

前端 未结 7 1759
天涯浪人
天涯浪人 2020-11-28 01:17

When would you use collect() vs reduce()? Does anyone have good, concrete examples of when it\'s definitely better to go one way or the other?

7条回答
  •  眼角桃花
    2020-11-28 01:59

    The reason is simply that:

    • collect() can only work with mutable result objects.
    • reduce() is designed to work with immutable result objects.

    "reduce() with immutable" example

    public class Employee {
      private Integer salary;
      public Employee(String aSalary){
        this.salary = new Integer(aSalary);
      }
      public Integer getSalary(){
        return this.salary;
      }
    }
    
    @Test
    public void testReduceWithImmutable(){
      List list = new LinkedList<>();
      list.add(new Employee("1"));
      list.add(new Employee("2"));
      list.add(new Employee("3"));
    
      Integer sum = list
      .stream()
      .map(Employee::getSalary)
      .reduce(0, (Integer a, Integer b) -> Integer.sum(a, b));
    
      assertEquals(Integer.valueOf(6), sum);
    }
    

    "collect() with mutable" example

    E.g. if you would like to manually calculate a sum using collect() it can not work with BigDecimal but only with MutableInt from org.apache.commons.lang.mutable for example. See:

    public class Employee {
      private MutableInt salary;
      public Employee(String aSalary){
        this.salary = new MutableInt(aSalary);
      }
      public MutableInt getSalary(){
        return this.salary;
      }
    }
    
    @Test
    public void testCollectWithMutable(){
      List list = new LinkedList<>();
      list.add(new Employee("1"));
      list.add(new Employee("2"));
    
      MutableInt sum = list.stream().collect(
        MutableInt::new, 
        (MutableInt container, Employee employee) -> 
          container.add(employee.getSalary().intValue())
        , 
        MutableInt::add);
      assertEquals(new MutableInt(3), sum);
    }
    

    This works because the accumulator container.add(employee.getSalary().intValue()); is not supposed to return a new object with the result but to change the state of the mutable container of type MutableInt.

    If you would like to use BigDecimal instead for the container you could not use the collect() method as container.add(employee.getSalary()); would not change the container because BigDecimal it is immutable. (Apart from this BigDecimal::new would not work as BigDecimal has no empty constructor)

提交回复
热议问题