Java Stream API的collect方法

4
有一个名为Person的类:
class Person {
    private String id;
    private String name;
    private int age;
    private int amount;
}

我使用外部文件的行创建了一个包含PersonHashMap

001,aaa,23,1200
002,bbb,24,1300
003,ccc,25,1400
004,ddd,26,1500

Mainclass.java

public class Mainclass {
public static void main(String[] args) throws IOException {
    List<Person> al = new ArrayList<>();
    Map<String,Person> hm = new HashMap<>();
    try (BufferedReader br = new BufferedReader(new FileReader("./person.txt"))) {
        hm = br.lines().map(s -> s.split(","))
                .collect(Collectors.toMap(a -> a[0], a-> new Person(a[0],a[1],Integer.valueOf(a[2]),Integer.valueOf(a[3]))));
    }
}

对于 HashMap,它可以正常工作。

如何实现相同的功能,但针对的是 ArraList

我尝试了:

    al = br.lines().map(s -> s.split(","))
                    .collect(Collectors.toList(a -> new Person(a[0],a[1],Integer.valueOf(a[2]),Integer.valueOf(a[3]))));

(IntelijIdea 下划线标出“a[0]”,并显示“期望数组类型,找到:lambda 参数”)
5个回答

11
你应该使用map将每个数组映射到相应的Person实例:
al = br.lines().map(s -> s.split(","))
               .map (a -> new Person(a[0],a[1],Integer.valueOf(a[2]),Integer.valueOf(a[3])))
               .collect(Collectors.toList());

顺便提一句,Collectors.toList() 返回的是一个 List,而不是 ArrayList(即使默认实现确实返回 ArrayList,你也不能指望它会始终如一)。


1
当属性具有问题中所示的int值时,使用Integer.parseInt比使用Integer.valueOf更可取,以避免不必要的装箱为Integer对象,然后再进行拆箱。此外,我会在Person类中添加一个static工厂方法,例如Person.parse(String)来执行转换。 - Holger

2
你需要在尝试收集之前将其映射到“Person”对象:

您需要在尝试collect之前将其mapPerson对象:

最初的回答
.map(s -> s.split(","))
.map(a -> new Person(a[0],a[1],Integer.valueOf(a[2]),Integer.valueOf(a[3])) //here
.collect(Collectors.toList())

1
为什么要映射两次?你可以直接这样做,
.map(s -> {
            String[] parts = s.split(",");
            return new Person(parts[0],parts[1],Integer.valueOf(parts[2]),Integer.valueOf(parts[3]));
        }).collect(Collectors.toList());

1
我建议在你的人类中添加一个静态方法(或相应的构造函数),用于解析CSV字符串:
public static Person fromCSV(String csv) {
    String[] parts = csv.split(",");
    if (parts.length != 4) {
        throw new IllegalArgumentException("csv has not 4 parts");
    }
    return new Person(parts[0], parts[1], Integer.parseInt(parts[2]), Integer.parseInt(parts[3]));
}

要读取行,您可以选择使用 Files.lines()。使用所有这些,您可以使用此创建List<Person>
try (Stream<String> lines = Files.lines(Paths.get("./person.txt"))) {
    List<Person> persons = lines
            .map(Person::fromCSV)
            .collect(Collectors.toList());
}

0
你所做的是正确的,只是缺少了在collect中创建Person对象的步骤。相反,你可以在map方法内部创建该对象并返回,然后使用collect方法和Collectors.toList()方法。下面的代码片段将更好地说明我的意思:
al= br.lines()
      .map(s -> {
                    String[] subStrings = s.split(",");
                    return new Person(subStrings[0], subStrings[1], Integer.valueOf(subStrings[2]), Integer.valueOf(subStrings[3]));
                })
      .collect(Collectors.toList());

这种方式只使用一次map方法,并返回所需的对象,collect方法将其合并为List。如果您希望它是ArrayList,则可以使用Collections框架将List转换为ArrayList,但我认为List对于您的操作应该足够了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接