116

Maybe this is very simple but I'm actually a noob on Java 8 features and don't know how to accomplish this. I have this simple line that contains the following text:

"Key, Name"

and I want to convert that line into a String array, separating each value by the comma (,), however, I also want to trim every field before returning the final array, so I did the following:

Arrays.stream(line.split(",")).map(String::trim).toArray();

However, this returns an Object[] array rather than a String[] array. Upon further inspection, I can confirm that the contents are actually String instances, but the array itself is of Object elements. Let me illustrate this, this is what the debugger says of the returned object:

Object[]:
    0 = (String) "Key"
    1 = (String) "Name"

As far as I can tell, the problem is in the return type of the map call, but how can I make it return a String[] array?

2 Answers 2

187

Use toArray(size -> new String[size]) or toArray(String[]::new).

String[] strings = Arrays.stream(line.split(",")).map(String::trim).toArray(String[]::new);

This is actually a lambda expression for

.toArray(new IntFunction<String[]>() {
        @Override
        public String[] apply(int size) {
            return new String[size];
        }
    });

Where you are telling convert the array to a String array of same size.

From the docs

The generator function takes an integer, which is the size of the desired array, and produces an array of the desired size. This can be concisely expressed with an array constructor reference:

 Person[] men = people.stream()
                      .filter(p -> p.getGender() == MALE)
                      .toArray(Person[]::new);

Type Parameters:

A - the element type of the resulting array

Parameters:

generator - a function which produces a new array of the desired type and the provided length

Sign up to request clarification or add additional context in comments.

5 Comments

Can you please explain what is the String[]::new method reference doing and how can I do the same using a regular lambda expression? (I see that it yields a "value" of the int type, but it doesn't make sense to me).
By the way, the trim step becomes obsolete when you make the white-space part of the delimiter, e.g. line.split("\\s*,\\s*") so it isn’t contained in the result strings in the first place. Then, you don’t need the Stream operation at all: String[] result=line.split("\\s*,\\s*");. Or you can use String[] result=line.split(","); Arrays.asList(result).replaceAll(String::trim);. You don’t need a Stream for every task…
Sorry to necro-post but the goal of the code was to excuse the use of map, I actually tried to force a use for streams in this case.
This is beautiful, but what if the array I'm dealing with is of a type CompletableFuture<Texture>. CompletableFuture<Texture>::new does not work.
What about toArray for classes?
6

String[]::new is a function that invokes the new "pseudo-method" for the String[] type just like String::trim is a function that invokes the real trim method of the String type. The value passed to the String::new function by toArray is the size of the collection on the right-hand side of the .toArray() method invocation.

If you replaced String[]::new with n->new String[n] you might be more comfortable with the syntax just like you could replace String::trim with the less cool s->s.trim()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.