344

Basically I have an ArrayList of locations:

ArrayList<WorldLocation> locations = new ArrayList<WorldLocation>();

below this I call the following method:

.getMap();

the parameters in the getMap() method are:

getMap(WorldLocation... locations)

The problem I'm having is I'm not sure how to pass in the WHOLE list of locations into that method.

I've tried

.getMap(locations.toArray())

but getMap doesn't accept that because it doesn't accept Objects[].

Now if I use

.getMap(locations.get(0));

it will work perfectly... but I need to somehow pass in ALL of the locations... I could of course make keep adding locations.get(1), locations.get(2) etc. but the size of the array varies. I'm just not use to the whole concept of an ArrayList

What would be the easiest way to go about this? I feel like I'm just not thinking straight right now.

MJ93
  • 4,966
  • 8
  • 32
  • 50
  • Beware of [Java automatically converting collections to arguments arrays?](http://stackoverflow.com/questions/33461138/java-automatically-converting-collections-to-arguments-arrays) – Vadzim Jan 23 '17 at 16:38

5 Answers5

462

Source article: Passing a list as an argument to a vararg method


Use the toArray(T[] arr) method.

.getMap(locations.toArray(new WorldLocation[0]))

Here's a complete example:

public static void method(String... strs) {
    for (String s : strs)
        System.out.println(s);
}

...
    List<String> strs = new ArrayList<String>();
    strs.add("hello");
    strs.add("world");
    
    method(strs.toArray(new String[0]));
    //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 2
    How costly this operation would be in terms of memory & speed? – mindreader Feb 21 '14 at 23:53
  • This will not work without a warning if there are further templates involved. E.g. `someMethod(someList.toArray(new ArrayList[someList.size()]))` will give you a warning that is very annoying if the function is more than a few lines long (because you can either suppress it for the whole function or you have to create the array in an additional step and suppress the warning on the variable you store it. – Qw3ry Jan 20 '17 at 10:31
  • 47
    Apparently the fastest approach is giving a size of zero rather than the size of the array. In short, it's because the compile-time constant enables the use of an optimized method. https://shipilev.net/blog/2016/arrays-wisdom-ancients/ – geg May 15 '17 at 15:26
  • 3
    @JoshM. Java needs a lot of things. ;) I also (coming from a C# background) miss index operators. Working with dictionaries is much more smooth in C# than working with HashMaps in Java. – Per Lundberg Jan 15 '19 at 09:12
  • @PerLundberg -- Totally agree. Also a primarily C# developer currently working w/Java8. Maybe 10/11 will be better. :-P – Josh M. Jan 15 '19 at 17:41
  • Java 10+ is a bit better with local variable inference, but big changes like value types are still in the planning stage for the language. I really hope we get non-erased generics also some day... :) (also in Java 8 at the moment but moving towards Java 11) – Per Lundberg Jan 15 '19 at 19:45
  • gaaaaaaaaaaaaaaaaaaaaaaaa more java voodoo. thanks for this answer! – granadaCoder Apr 04 '19 at 20:01
  • This works just fine in Java 8, thanks for sharing. – jpruiz114 Jul 10 '20 at 19:42
  • Unless you are using a older version of java. I personally opt for: strs.stream().toArray(String[]::new); Not that it is fast, but I like the idea that you do not have to use strs.size(). – ormurin Dec 23 '20 at 08:14
  • I got a warning suggesting zero-length arrays are better and stumbled into this: https://github.com/mybatis/mybatis-3/commit/56cc0e467f7463a5ad4cb00641c914731aa53be7 – Pat Lee Jul 27 '21 at 09:09
88

In Java 8:

List<WorldLocation> locations = new ArrayList<>();

.getMap(locations.stream().toArray(WorldLocation[]::new));
jmhostalet
  • 4,399
  • 4
  • 38
  • 47
  • 4
    this is java voodoo, but better java (8) voodoo.. thanks! – granadaCoder Apr 04 '19 at 20:27
  • 9
    `locations.toArray(WorldLocations[]::new)` also seems to works since java 11 (Without the `.stream()`) – Eran Medan Jun 11 '20 at 12:53
  • @EranMedan toArray works always without stream, regardless of the Version see: https://docs.oracle.com/javase/1.5.0/docs/api/java/util/List.html – kaba713 Jul 28 '20 at 07:11
  • @kaba713 yes, but not the overload that accepts an `IntFunction`, which was added in Java 11 :) https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html#toArray(java.util.function.IntFunction) – Eran Medan Jul 29 '20 at 12:43
17

A shorter version of the accepted answer using Guava:

.getMap(Iterables.toArray(locations, WorldLocation.class));

can be shortened further by statically importing toArray:

import static com.google.common.collect.toArray;
// ...

    .getMap(toArray(locations, WorldLocation.class));
tkruse
  • 10,222
  • 7
  • 53
  • 80
2

You can do:

getMap(locations.toArray(new WorldLocation[locations.size()]));

or

getMap(locations.toArray(new WorldLocation[0]));

or

getMap(new WorldLocation[locations.size()]);

@SuppressWarnings("unchecked") is needed to remove the ide warning.

Sylhare
  • 5,907
  • 8
  • 64
  • 80
Imar
  • 499
  • 6
  • 9
-1

Though it is marked as resolved here my KOTLIN RESOLUTION

fun log(properties: Map<String, Any>) {
    val propertyPairsList = properties.map { Pair(it.key, it.value) }
    val bundle = bundleOf(*propertyPairsList.toTypedArray())
}

bundleOf has vararg parameter

Nikhilesh Patve
  • 1,760
  • 3
  • 13
  • 31