8

Starting with Java 8 so need a bit of time to get used to it. It's a classical problem, I've an array of objects that I want to transform.

Before Java8 the ideal code would be (no null pointers):

P[] outputArray = new P[inputArray.length];
for (int i =0; i< inputArray.length; i++ )
{
    outputArray [i] = inputArray[i].transformToP();
}

What is the best version in Java8 ?

2

2 Answers 2

12

Using the Stream API it's quite simple:

P[] outputArray = Arrays.stream(inputArray).map(e -> e.transformToP()).toArray(P[]::new);

Also method reference can be used (suppose that I is the type of input elements):

P[] outputArray = Arrays.stream(inputArray).map(I::transformToP).toArray(P[]::new);

Note that you may have problems if transformToP() method throws checked exceptions. In this case convert them to unchecked ones or consult this question.

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

2 Comments

There is also a Stream.of(inputArray) if you prefer that over Arrays.stream(inputArray).
@Keppil, yes, I guess it's the matter of style.
7

Using a stream over an array is a fine technique as described in Tagir Valeev's answer. However, don't forget about Arrays.setAll. This is a handy shortcut for setting all the elements of an array based on index. To transform an array to a new array by some function, you could do this:

P[] outputArray = new P[inputArray.length];
Arrays.setAll(outputArray, i -> inputArray[i].transform());

You don't have to copy it into a new array. If you want to transform the array in-place, you could do this:

Arrays.setAll(array, i -> array[i].transform());

There is also a parallel variation parallelSetAll.

Under the covers this is just an IntStream.range over the indexes of the input array, but it's sometimes darned convenient for quick one-liners.

5 Comments

Nice addition, upvote. Though OP's transformToP suggests that outputArray type P differs from inputArray type. By the way it would be very useful to have something like Arrays.replaceAll(array, fn) which passes to the fn not the array index, but the current value, so you can write Arrays.replaceAll(array, P::transform);
@TagirValeev Thanks. There indeed are a bunch of things "missing" from Arrays that would be quite useful. The problem is that Arrays is already too cluttered and any addition would also imply adding subrange variations and primitive specializations.
I see. I always wonder if it's possible to add such methods directly to the array type (using like array.setAll(i -> array[i].transform());). There's already a clone() method which is available in array type directly. Why not adding more array-related methods instead of cluttering the Arrays class? The primitive specializations would just be located in the corresponding primitive array types. Well, it may require significant changes in the language, but it would make the code much clearer. The javac may just convert such calls to static methods invocations.
@TagirValeev Known problem. :-) Unfortunately the clone() method and length field of arrays are quite special-cased in the language. There are some ideas floating around to make arrays implement some interface, so these things would be declared explicitly, and possibly even extended. See John Rose's "Arrays 2.0" talk at the 2012 JVMLS. Note however that although some of this has been prototyped, none of it is committed for JDK 9 as far as I know.
Nice one, for the time being my favorite as it creates less objects (yes, yes sometimes it's important)

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.