【问题标题】:How to convert a list with properties to a another list the java 8 way?java - 如何以java 8方式将具有属性的列表转换为另一个列表?
【发布时间】:2017-02-23 09:50:28
【问题描述】:

有一个带有属性 Developer 的列表 A。开发者架构喜欢这样:

@Getter
@Setter
public class Developer {
    private String name;
    private int age;

    public Developer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Developer name(String name) {
        this.name = name;
        return this;
    }

    public Developer name(int age) {
        this.age = age;
        return this;
    }
}

列表 A 的属性:

List<Developer> A = ImmutableList.of(new Developer("Ivan", 25), new Developer("Curry", 28));

需要将List A转换成List B,属性为ProductManager,属性与List A相同。

@Getter
@Setter
public class ProductManager {
    private String name;
    private int age;

    public ProductManager(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public ProductManager name(String name) {
        this.name = name;
        return this;
    }

    public ProductManager name(int age) {
        this.age = age;
        return this;
    }
}

在过去,我们会编写如下代码:

public List<ProductManager> convert() {
    List<ProductManager> pros = new ArrayList<>();
    for (Developer dev: A) {
        ProductManager manager = new ProductManager();
        manager.setName(dev.getName());
        manager.setAge(dev.getAge());
        pros.add(manager);
    }
    return pros;
}

我们如何使用 Java 8 以更优雅、更简洁的方式编写上述内容?

【问题讨论】:

  • 这里真正的问题是为什么DeveloperProductManager 似乎没有从封装nameage 的通用超类Person 继承。在你升级到漂亮的 Java8 之前,你可能应该得到正确的设计。
  • @JimGarrison 是的,我同意你的观点,我需要更加关注基本面。如果属性比较多,可能超过20个,构造函数不能直接使用,如何转换?
  • 如果DeveloperProductManager 有一个共同的基类Person,定义了所有共同的属性,那么在两个类中定义一个带有Person 参数的构造函数就没有问题。这些构造函数只会委托给 Person 基类的构造函数来完成这项工作,因此它只需要实现一次。请注意,这是一种既定模式,即所有标准 Collection 类型都提供了一个构造函数,该构造函数接受 Collection 参数以进行复制。

标签: java list collections java-8 refactoring


【解决方案1】:

大概是这样的:

List<ProductManager> B = A.stream()
        .map(developer -> new ProductManager(developer.name, developer.age))
        .collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    如果您可以在 ProductManger 中添加 belwo 构造函数

    public ProductManager(Developer d) {
        this.name = d.getName();
        this.age = d.getAge();
    }
    

    然后使用构造函数引用进行转换

        List<Developer> developers = Arrays.asList(new Developer("abc", 25));
        List<ProductManager> managers = developers.stream().map(ProductManager::new).collect(Collectors.toList());
        System.out.println(managers);
    

    否则你可以提供自定义映射器

    Function<Developer, ProductManager> mapper = d -> new ProductManager(d.getName(), d.getAge()); 
    

    map 函数中使用它

    输出

    [ProductManager [name=abc, age=25]]
    

    【讨论】:

    • 如果属性比较多,可能超过20个,构造函数不能直接使用,如何转换?
    • 在上述映射器函数中,不使用构造函数,而是创建一个产品经理对象,设置它的所有属性并返回它
    【解决方案3】:

    你必须使用类似下面的东西:

    List<ProductManager> B = A.stream()
            .map(developer -> new ProductManager(developer.getName(), developer.getAge()))
            .collect(Collectors.toList());
    

    // 对于大量的属性,假设属性具有相似的名称 //其他名称不同的请参考this

    List<ProductManager> B = A.stream().map(developer -> {
                ProductManager productManager = new ProductManager();
                try {
                    PropertyUtils.copyProperties(productManager, developer);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return productManager;
            }).collect(Collectors.toList());
    
            B.forEach(System.out::println);
    

    【讨论】:

    【解决方案4】:

    如果有更多的属性,可能超过20个,以及构造函数 不能直接使用,怎么转换?

    如果要设置的属性超过 3-4 个,则应使用 Builder,如下所示:

    List<Developer> A = ImmutableList.of(new Developer("Ivan", 25),
                                         new Developer("Curry", 28));
    
    Function<Developer, ProductManager> converter = dev -> new ProductManagerBuilder()
            .setAge(dev.getAge())
            .setName(dev.getName())
            .setProperty1(dev.getProperty1())
            .setProperty2(dev.getProperty2())
            ...
            .build();
    
    List<ProductManager> productManagers = A.stream()
                                            .map(converter)
                                            .collect(toList());
    

    【讨论】:

    • 你的意思是使用构建模式?这是正确的。然后我的问题是如何在内部映射中编写函数体,而不是构造函数。 Builder 模式在这个示例中就像构造函数一样工作,所以这不是我的意图,无论如何,谢谢。
    【解决方案5】:

    Java 16 已将集合 api 更新为 .toList() 而不是 .collect(Collectors.toList())

    List<ProductManager> B = A.stream()
            .map(developer -> new ProductManager(developer.name, developer.age))
            .toList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-12
      • 1970-01-01
      • 2014-09-28
      • 2021-10-11
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多