harp1814
harp1814

Reputation: 1658

Java Stream API collect method

There is class Person:

class Person {
    private String id;
    private String name;
    private int age;
    private int amount;
}

and I have created HashMap of Person using external file contains lines:

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]))));
    }
}

}

It works fine for HashMap.

How to do the same for ArrayList?

I tried:

    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 is underlined in red "a[0]" and says "Array type expected,found : lambda parameter")

Upvotes: 4

Views: 1080

Answers (5)

Samuel Philipp
Samuel Philipp

Reputation: 11042

I would recommend adding a `static method (or according constructor) to your person class which parses the CSV string:

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]));
}

To read the lines you can alternatively use Files.lines(). Using all that you can use this to create you List<Person>:

try (Stream<String> lines = Files.lines(Paths.get("./person.txt"))) {
    List<Person> persons = lines
            .map(Person::fromCSV)
            .collect(Collectors.toList());
}

Upvotes: 1

vatsal gosar
vatsal gosar

Reputation: 187

What you did is on correct lines, only thing missing is that you create the Person object in collect, instead you could create it inside the map method itself and return that and use the collect method with Collectors.toList() method. Below code snippet will give a good idea of what I am trying to convey:

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());

This way you use the map method only once, and return the object that is needed which the collect method consolidates into a List. If you want it to be an ArrayList you can use Collections framework to cast List to ArrayList, but I think List should be fine for your operations.

Upvotes: 0

chaitanya89
chaitanya89

Reputation: 847

Why to map twice? You can directly do this,

.map(s -> {
            String[] parts = s.split(",");
            return new Person(parts[0],parts[1],Integer.valueOf(parts[2]),Integer.valueOf(parts[3]));
        }).collect(Collectors.toList());

Upvotes: 1

Naman
Naman

Reputation: 31868

You need to map it to the Person object before trying to collect it:

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

Upvotes: 2

Eran
Eran

Reputation: 393771

You should use map in order to map each array to a corresponding Person instance:

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());

BTW, Collectors.toList() returns a List, not an ArrayList (even if the default implementation does return ArrayList, you can't count on that).

Upvotes: 11

Related Questions