Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda function in Java skips elements

I have a row which I need to parse which looks like:

@UNIT,a,b,c,,,,d,e,,,

and I expect Java to store the following values in a list:

[0] => a
[1] => b
[2] => c
[3] => null
[4] => null
[5] => null
[6] => d
[7] => e
[8] => null
[9] => null
[10] => null

I want to comma separate the values by comma and replace empty values with null.

I archive most of the part with the following code:

metaObject.unit = Arrays.stream(line
        .split(","))
        .skip(line.startsWith("@UNIT,") ? 1 : 0)
        .map(String::trim)
        .map(s -> " ".equals(s) || "".equals(s) || "_".equals(s)? null : s)
        .collect(Collectors.toList());

Where metaObject.unit is defined as List<String> unit = new ArrayList<String>();

The problem is that Java ignores the empty elements which occure after the last non-empty element. The output I get in the given case is:

[0] => a
[1] => b
[2] => c
[3] => null
[4] => null
[5] => null
[6] => d
[7] => e

I do not understand why Java does not threat the empty elements as before. Is there any trick to get this fixed?

like image 704
Drudge Avatar asked Oct 07 '15 15:10

Drudge


People also ask

Can lambda throw exception Java?

A lambda expression cannot throw any checked exception until its corresponding functional interface declares a throws clause. An exception thrown by any lambda expression can be of the same type or sub-type of the exception declared in the throws clause of its functional interface.

How do you handle exception thrown by lambda expression?

Because IOException is a checked exception, we must handle it explicitly. We have two options. First, we may simply throw the exception outside of our method and take care of it somewhere else. Alternatively, we can handle it inside the method that uses a lambda expression.

Can lambda expression have multiple lines Java?

In Java 8, it is also possible for the body of a lambda expression to be a complex expression or statement, which means a lambda expression consisting of more than one line. In that case, the semicolons are necessary. If the lambda expression returns a result then the return keyword is also required.


1 Answers

The problem actually comes from line.split(",").

By default, quoting the Javadoc of split(regex):

Trailing empty strings are therefore not included in the resulting array.

So the result of this call is [@UNIT, a, b, c, , , , d, e].

What you want is to include the trailing empty strings, so you need to call line.split(",", -1) (note the negative second parameter). Quoting the Javadoc of split(regex, limit), about the limit parameter:

If n is non-positive then the pattern will be applied as many times as possible and the array can have any length.

Corrected code:

metaObject.unit = Arrays.stream(line
    .split(",", -1))
    .skip(line.startsWith("@UNIT,") ? 1 : 0)
    .map(String::trim)
    .map(s -> s.isEmpty() || "_".equals(s) ? null : s)
    .collect(Collectors.toList());

(Note that I removed the call to " ".equals(s) since if that were the case, the preceding call to trim would have made that String an empty String, and, as Holger points out in his comment, I replaced "".equals(s) with the cleaner s.isEmpty()).

like image 69
Tunaki Avatar answered Oct 24 '22 03:10

Tunaki