Подтвердить что ты не робот

Потоки Java 8 на строковых массивах

У меня есть одна строка формата:

row1col1 row1col2
row2col1 row2col2
row3col1 row3col2

и т.д.

Я хочу извлечь каждый элемент и построить массив объектов со свойствами вроде этого:

new MyObject(row1col1, row1col2); 

Я новичок в Java 8 и Streams, и я хотел бы узнать, как я могу добиться этого без циклов.

Обычно я использовал бы String.split('\n') для накопления строк в массиве String

И затем цикл, в котором для каждой строки я бы снова разделился на разделитель пространства и с результирующим массивом из двух элементов (row1col1 row1col2) построил мой объект, пока не будет больше строк для обработки.

Вот так:

String sausage = "row1col1 row1col2\nrow2col1 row2col2\nrow3col1 row3col2";
String[] rows = sausage.split("\n");

for (String row : rows) {
    String[] objectData = u.split("\\s+");
    MyObject myObject = new MyObject(objectData[0], objectData[1]);
    myObjectList.add(myObject);
}

Может ли кто-нибудь объяснить мне, как достичь этого с потоками и какой механизм за этим позволяет мне это сделать?

Является ли это даже правильным способом мышления при увеличении количества элементов, потому что из всех примеров, которые я видел, потоки фокусируются на фильтрации, сборе или вообще заданном наборе элементов, получают второстепенный набор, применяющий некоторые критерии.

4b9b3361

Ответ 1

Простым способом было бы создать Pattern с разделителем строк и разделить вход String на Stream. Затем каждая строка разделяется пробелом (сохраняя только 2 части) и отображаться на MyObject. Наконец, массив создается с результатом.

public static void main(String[] args) {
    String str = "row1col1 row2col2\r\nrow2col1 row2col2\r\nrow3col1 row3col2";

    MyObject[] array =
        Pattern.compile(System.lineSeparator(), Pattern.LITERAL)
               .splitAsStream(str)
               .map(s -> s.split("\\s+", 2))
               .map(a -> new MyObject(a[0], a[1]))
               .toArray(MyObject[]::new);

    System.out.println(Arrays.toString(array));
}

Использование splitAsStream может быть выгодным по сравнению с Stream.of(...), если вход String длинный.

Я предположил в коде, что разделитель строк String был разделителем строк по умолчанию (System.lineSeparator()) ОС, но вы можете изменить это, если это не так.


Вместо этого, если вы читаете файл, вы можете использовать Files.lines() для удержания Stream всех строк в файле:

MyObject[] array = Files.lines(path)
                        .map(s -> s.split("\\s+", 2))
                        .map(a -> new MyObject(a[0], a[1]))
                        .toArray(MyObject[]::new);

System.out.println(Arrays.toString(array));

Ответ 2

Вы можете создать Stream из String, которые представляют один экземпляр MyObject, и преобразовать каждый из них в ваш экземпляр MyObject (сначала разделив их, а затем создав экземпляр MyObject):

List<MyObject> list = 
   Stream.of(inputString.split("\n"))
      .map (s -> s.split(" "))
      .filter (arr -> arr.length == 2) // this validation may not be necessary
                                       // if you are sure each line contains 2 tokens
      .map (arr -> new MyObject(arr[0],arr[1]))
      .collect(Collectors.toList());