Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 streams on string arrays

I have a single String of format:

row1col1 row1col2
row2col1 row2col2
row3col1 row3col2

and so on...

I want to extract each item and build an array of objects with properties like this:

new MyObject(row1col1, row1col2); 

I am new to Java 8 and Streams and I would like to find out how can I achieve this without loops.

Normally I would use a String.split('\n') for accumulating the rows into an array of String

And then a loop where for each line I would split again on the space separator and with the resulting array of the two elements (row1col1 row1col2) build my object, until there are no more rows to process.

Like this:

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

Can anyone explain me how to achieve the same with streams and what is the mechanism behind that allows me to do so?

Is this even a valid way of thinking when increasing the number of elements because from all the examples I've seen the streams focus on filtering, collecting or generally given a set of elements retrieve a minor set applying some criterias.

like image 742
Lucian Enache Avatar asked Dec 11 '15 08:12

Lucian Enache


2 Answers

A simple way would be to create a Pattern with the line separator and split the input String as a Stream. Then, each line is split with a space (keeping only 2 parts) and mapped to a MyObject. Finally, an array is constructed with the result.

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

Using splitAsStream can be advantageous over Stream.of(...) if the input String is long.

I assumed in the code that the line separator of the String was the default line separator (System.lineSeparator()) of the OS but you can change that if it is not.


Instead, if you are reading from a file, you could use Files.lines() to get a hold of a Stream of all the lines in the file:

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));
like image 84
Tunaki Avatar answered Oct 27 '22 00:10

Tunaki


You could generate a Stream of Strings that represent a single MyObject instance, and transform each of them to your MyObject instance (by first splitting them again and then constructing a MyObject instance) :

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());
like image 26
Eran Avatar answered Oct 27 '22 00:10

Eran