Parzavil
Parzavil

Reputation: 388

Is there a difference between String[]::new and new String[] in java?

I am converting an ArrayList to an Array using

ArrayList<String> var1 = new ArrayList<>();
for(condition){
// Add items to var1
}

return var1.toArray(new String[]{})

My IDE is recommending i change the last line to

return var1.toArray(String[]::new)

Is this just better convention or is there also some benefits to compile-time or memory usage.

Upvotes: 1

Views: 879

Answers (2)

rzwitserloot
rzwitserloot

Reputation: 103893

String[]::new is a function. It does not create a new string array, it defines a function that makes new string arrays. It's like the difference between a cake, and a recipe to make a cake. One consists of flour and icing and all that. The other one is just words and paper. Completely different things, but related, in that the recipe lets you make cake (any number of them, even!)

String[]::new is shorthand* for:

public String[] makeNewStringArray(int size) {
    return new String[size];
}

Merely writing that doesn't make any string arrays at all; calling that function would make one string array each time it is invoked.

Example:

IntFunction<String[]> stringArrayMaker = String[]::new;
String[] size10 = stringArrayMaker.apply(10);

Okay, so what about the recommendation?

What you've written is slightly non-standard; new String[0] is more standard. So let's compare new String[0] versus String[]::new.

The only point of this parameter is to allow the arraylist to know what type you want. You'd think the arraylist already knows (it is an ArrayList<String> after all!) but due to generics erasure (a rather complex topic), there is no way for the code of toArray to know what you want, therefore, you must specify.

new String[0] ends up making a 0-length string array which is then immediately discarded. This feels wasteful, but garbage collection being what it is, 'quick garbage' (objects made and discarded very quickly and never shared with other threads) is almost entirely free. This method (toArray(T[])) works as follows: If the incoming array is as large or larger than is needed, it is filled, and returned. If it is too small, a new array is created with the same component type of the right size, that one is filled, and that one is returned.

You'd think, therefore, that var1.toArray(new String[var1.size()]) is the most efficient. But JMH tells me there is no difference at all. Which goes to show how incredibly efficient java is at dealing with short lived garbage (when I say 'short lived garbage is free', I mean it. It's almost impossible to witness the cost of it).

The functional approach (where you pass String[]::new) means that this function will take care of making the array, and toArray itself just relies on what it gets. This.. also works fine. It ends up making a method in your class file someplace.

So, it really doesn't matter. I find the IDE being overly preachy here. String[]::new makes a new method, and the overhead in class space alone probably means it ends up being less efficient, even though the creation of the garbage is more easily understandable inefficiency.

But, we're really nitpicking here. Literally talking about nanoseconds - you're never going to notice.

Do whatever you find is most readable (though I would steer clear of new String[]{} - nothing wrong with it perse, but it's not very common and it has no benefits over new String[0] - might as well do what the community does if it doesn't otherwise matter).

*) This is slightly oversimplified, but not by much.

Upvotes: 8

Cerus
Cerus

Reputation: 141

"String[]::new" is a method reference. Its basically the same as "new String[]". See Method References for more detail.

Upvotes: -6

Related Questions