首页 > 解决方案 > 在java中使用收集器进行分组操作后的转换

问题描述

我有一个简单的练习代码,其中有一个简单的 Person 对象列表。

我想做的是根据他们的年龄是奇数的偶数对它们进行分区,然后如果它们属于偶数组,则将它们的名称转换为大写,否则将名称转换为小写。

我面临的困难是使用 collect() 操作执行此转换。

这是简单的人类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@AllArgsConstructor
@Data
@Builder
@NoArgsConstructor
public class Person {

    private String name;

    private Gender gender;

    private int age;

    @Override
    public String toString() {
        return String.format("%s -- %s -- %d", name, gender, age);
    }

}

这是一个简单的人员对象列表

public static List<Person> getExpandedList() {
        return Arrays.asList(new Person("Sara", Gender.FEMALE, 20), new Person("Sara", Gender.FEMALE, 22),
                new Person("Bob", Gender.MALE, 20), new Person("Paula", Gender.FEMALE, 32),
                new Person("Paul", Gender.MALE, 31), new Person("Jack", Gender.MALE, 2),
                new Person("Jack", Gender.MALE, 72), new Person("Jill", Gender.FEMALE, 12),
                new Person("Mahi", Gender.FEMALE, 11), new Person("Natalie", Gender.FEMALE, 3));
    }

以下是我试图用于转换的代码。

所以我希望 Mahi、Natalie 和 Paul 的名字全部小写,其余的名字应该全部大写,我希望整个人都返回对象,而不仅仅是名字。

这是我正在尝试的代码

import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.*;

public class PartitioningWithCollectors {

    public static void main(String[] args) {
        List<Person> personList = StreamsPracticeUtil.getExpandedList();

 
        Map<Boolean, List<Person>> updatedPersons = personList.stream()
                .collect(partitioningBy(person -> person.getAge() % 2 == 0,
                        //filtering(person -> person.getAge() % 2 == 0,
                        mapping(person -> Person.builder()
                                .age(person.getAge())
                                .gender(person.getGender())
                                .name(person.getName().toUpperCase())
                                .build(), toList())));//);

        System.out.println(updatedPersons);
    }

}

但是当然,问题是一旦我使用任何类型的过滤,分区的其他结果就消失了。

实际上,我想以功能方式执行以下操作

for (Person person : personList) {
            if (person.getAge() % 2 == 0) {
                person.setName(person.getName().toUpperCase());
            } else {
                person.setName(person.getName().toLowerCase());
            }
        }

        System.out.println(personList);

感谢我能得到的任何帮助。谢谢..!!

标签: javajava-streamcollect

解决方案


您可以在之前映射每个人.collect();

例如:

personList.stream()
                .map(SET_NAME_CASE)
                .collect(.....)

当 SET_NAME_CASE 是您的自定义函数时:

public static final UnaryOperator<Person> SET_NAME_CASE =
            source -> {
                    if(person.getAge % 2 == 0){
                       return Person.builder()                            
                                .name(person.getName().toUpperCase())
                                .build();
                    } else {
                       return Person.builder()                            
                                .name(person.getName().toLowerCase())
                                .build();
                    }
};

之后,您将拥有一个带有集合名称的 Person 对象。您可以进行任何分组,也可以设置其他字段 Person。更改@Builder@Builder(toBuilder = true),您将在流中添加任何映射并设置其他字段,例如:

  personList.stream()
                    .map(SET_NAME_CASE)
                    .map(
                         source -> Person.toBuilder()
                                    .age(person.getAge())
                                    .gender(person.getGender())
                                    .build()
                     )
                    .collect(.....)

推荐阅读