Initializing local variable to generic interface Below is my working code written as an exercise in wildcards in generics and Java 8 type inference.  My question will be about the commented line in union() method.  

I needed to create an instance of the interface type that does not include a static factory, so I was left with (seemingly) two choices:


Use concrete implementation (as in my code below)
Use Reflection to retrieve the actual run-time class and call its constructor (similar to my earlier question).


I chose to use the first approach and used a constructor of a concrete class HashSet&lt;E&gt; (that implements Set). I picked HashSet among other publicly available implementations rather arbitrarily.

My reasoning was that any would suffice, since it will be returned by a method as just Set&lt;E&gt; and, though it will retain its HashSet-specific members, they will not interfere with a client process. 

Was my decision safe and sound or is there a legitimate way to break my method code?

import java.util.*;


public class TypeInference {

    public static &lt;E&gt; Set&lt;E&gt; union (Set&lt;? extends E&gt; s1, Set&lt;? extends E&gt; s2) {
        Set&lt;E&gt; result = new HashSet&lt;E&gt;();  // or any other concrete Set
        result.addAll(s1);
        result.addAll(s2);
        return result;
    }

    public static void main(String[] args) {

        Set&lt;Integer&gt; ints = new TreeSet&lt;&gt;(Arrays.asList(1, 2, 3, 4, 5));
        Set&lt;Double&gt; doubles = new TreeSet&lt;&gt;(Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0));

        Set&lt;Number&gt; numbers = union(ints, doubles);
        System.out.println(numbers);
    }

}
This is as safe as your Set implementation for result. For example, swapping for a TreeSet gave the following error:

Exception in thread "main" java.lang.ClassCastException: 
            java.lang.Integer cannot be cast to java.lang.Double
    at java.lang.Double.compareTo(Double.java:49)
    at java.util.TreeMap.put(TreeMap.java:568)
    at java.util.TreeSet.add(TreeSet.java:255)
    at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
    at java.util.TreeSet.addAll(TreeSet.java:312)


This is understandable since TreeSet imposes an ordering, which in turns calls the to-be-added Collection-type's compareTo() with the existing entries. This has nothing to do with type incompatibility at compile-time (the code compiles), rather it's a limitation/feature of the TreeSet implementation.

In your linked question @rolfl suggested giving a Supplier to the method, which I will advocate here too:

public class TypeInference {

    public static &lt;E&gt; Set&lt;E&gt; union (Set&lt;? extends E&gt; s1, Set&lt;? extends E&gt; s2, 
            Supplier&lt;Set&lt;E&gt;&gt; supplier) {
        Set&lt;E&gt; result = supplier.get();
        result.addAll(s1);
        result.addAll(s2);
        return result;
    }

    public static &lt;E&gt; Set&lt;E&gt; union (Set&lt;? extends E&gt; s1, Set&lt;? extends E&gt; s2) {
        return union(s1, s2, () -&gt; new TreeSet&lt;&gt;(Comparator.comparing(Object::toString)));
    }

    public static void main(String[] args) {
        Set&lt;Integer&gt; ints = new TreeSet&lt;&gt;(Arrays.asList(1, 2, 3, 4, 5));
        Set&lt;Double&gt; doubles = new TreeSet&lt;&gt;(Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0));
        System.out.println(union(ints, doubles));
        System.out.println(union(ints, doubles, 
                () -&gt; new TreeSet&lt;&gt;(Comparator.comparing(Number::doubleValue))));
    }
}


The two-argument union() uses a TreeSet that compares by the entries' toString(), which lets us store both Integer and Double values together in the Set. Alternatively, calling union() with a TreeSet supplier that compares by Number.doubleValue() gives us only 5 distinct elements:

[1, 1.0, 2, 2.0, 3, 3.0, 4, 4.0, 5, 5.0]
[1, 2, 3, 4, 5]


Rounding back to your question, I suppose HashSet() is a reasonably safe bet, since it doesn't do anything fanciful other than the usual hashCode()/equals() checks. And as you correctly inferred, since the method return type is just a Set, callers of union() should not have any other expectations - the Set interface simply says "this is how I am intended to be used.".