Метод сбора Java Stream API - PullRequest
3 голосов
/ 25 июня 2019

Существует класс Person:

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

, и я создаю HashMap из Person s, используя внешний файл, содержащий строки:

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]» и говорит «Arrayожидаемый тип, найдено: лямбда-параметр ")

Ответы [ 5 ]

10 голосов
/ 25 июня 2019

Вы должны использовать 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, вы не можете рассчитывать на это).

2 голосов
/ 25 июня 2019

Вам нужно map передать его объекту Person, прежде чем пытаться collect сделать это:

.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 голос
/ 25 июня 2019

Я бы порекомендовал добавить статический метод (или соответствующий конструктор) к вашему классу person, который анализирует строку 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());
}
1 голос
/ 25 июня 2019

Зачем наносить на карту дважды? Вы можете сделать это напрямую,

.map(s -> {
            String[] parts = s.split(",");
            return new Person(parts[0],parts[1],Integer.valueOf(parts[2]),Integer.valueOf(parts[3]));
        }).collect(Collectors.toList());
0 голосов
/ 25 июня 2019

То, что вы сделали, в правильных строках, единственное, чего не хватает, - это создать объект Person в методе collect, вместо этого вы можете создать его внутри самого метода 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 должен подойти для ваших операций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...