2

I want to create a helper method which gets Collection type parameter to return a list. This is what I have now:

public class Helper {
    public static <T> T[] CollectionToArray(Collection<T> collection) {
        return collection.stream().toArray(Object[]::new); // Error
    }

    public static <T> T[] ListToArray(List<T> list) {
        return list.stream().toArray(Object[]::new); // Error
    }
}

public class IamSoNoob {
    public void PleaseHelpMe() {

        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();

        String[] arrayFromList = Helper.CollectionToArray(list); // Error
        String[] arrayFromSet = Helper.CollectionToArray(set); // Error

        String[] array = Helper.ListToArray(list); // Error
    }
}

My questions are:

  1. Is it possible to complete CollectionToArray(Collection<T>)?
    • If so, how?
    • Also, is it possible to pass List and Set as a parameter in the first place?
  2. Is it possible to complete ListToArray(List<T> list)?
    • If so, how?

But here are some restrictions due to my personal taste.

  1. I don't want to use @SuppressWarnings
  2. I really want to keep the part .stream().toArray(Object[]::new) (Java 8 part!)

And I have a feeling that I need to fix the part Object[]::new by using something like: <T extends Object> or <? extends T> but I can't really figure out.

Please help me out, and please provide an explanation as well, I am often confused by Generic and ?.

Naman
  • 27,789
  • 26
  • 218
  • 353
KimchiMan
  • 4,836
  • 6
  • 35
  • 41
  • 4
    If it were possible to construct an array from a generic type alone, `Stream.toArray()` wouldn't require any parameters. – shmosel Dec 02 '18 at 03:29
  • @shmosel Right, but I'd like to know the solution for my question – KimchiMan Dec 02 '18 at 03:36
  • 1
    You'll need to accept another parameter. Either `T[]` or `IntFunction`. – shmosel Dec 02 '18 at 03:37
  • 1
    @shmosel How about the unchecked assignment `(T[]) collection.toArray()` ? – Naman Dec 02 '18 at 03:38
  • 4
    @nullpointer That's begging for a ClassCastException. – shmosel Dec 02 '18 at 03:39
  • @shmosel Could you provide an example code please? – KimchiMan Dec 02 '18 at 04:14
  • 1
    Just copy the parameter from `Collection.toArray()` or `Stream.toArray()`. – shmosel Dec 02 '18 at 04:16
  • 3
    Whats the bad thing in just using `Collections.toArray(T[ ])`? Why don't you just do `String[] arrayFromList =list.toArray(new String[0]); ` ? Whats the reasoning behind writing your own methods when the standard libraries provide tested , trusted and well doing exactly what you want methods? – Ryotsu Dec 02 '18 at 04:28
  • @Ryotsu It can be `String` or `Integer` or `Double` ... I want to make the method as generic as possible – KimchiMan Dec 02 '18 at 05:24

1 Answers1

2

No, you absolutely cannot do it, if it were possible the library method Collection.toArray() would've given you the same type as your LHS but instead when you want the exact type as your LHS you have to use Collection.toArray(T[]) (even that comes with ArrayStoreExceptions i.e it is up to the programmer to provide the right type for the array), the reason being that in your toArray() you've specified Object[] to be your array and later you cannot cast it to any other type or else it will result in a ClassCastException.

The reason for all this hullabaloo is because of the way generics works i.e its a compile time thing and at runtime Java erases all type parameters to their upper bound types and hence losing type information which is required for creating arrays.

One safe way of doing it is by adding another paramter to you helper method as

public static <T> T[] CollectionToArray(Collection<T> collection, T[] arr) {

            return collection.stream().toArray(value ->Arrays.copyOf(arr,collection.size()));


        }

and using it as

String[] arrayFromList = Helper.CollectionToArray(list, new String[0]);

but then everybody's better off using Collection#toArray(T[]).

Ryotsu
  • 786
  • 6
  • 16