The most efficient and at the same time safe way of accomplishing this is as follows:
List<S> supers = List.copyOf( descendants );
The documentation of this function is here: oracle.com - Java SE 19 docs - List.copyOf() The documentation states that this function exists "Since: 10".
The use of this function has the following advantages:
- It is a neat one-liner.
- It produces no warnings.
- It does not require any typecast.
- It does not require the cumbersome
List<? extends S>
construct.
- It does not necessarily make a copy !!!
- Most importantly: it does the right thing. (It is safe.)
Why is this the right thing?
If you look at the source code of List.copyOf()
you will see that it works as follows:
- If your list was created with
List.of()
, then it will do the cast and return it without copying it.
- Otherwise, (e.g. if your list is an
ArrayList()
,) it will create a copy and return it.
If your original List<D>
is an ArrayList<D>
, then in order to obtain a List<S>
, a copy of the ArrayList
must be made. If a cast was made instead, it would be opening up the possibility of inadvertently adding an S
into that List<S>
, causing your original ArrayList<D>
to contain an S
among the D
s, which is a disastrous situation known as Heap Pollution (Wikipedia): attempting to iterate all the D
s in the original ArrayList<D>
would throw a ClassCastException
.
On the other hand, if your original List<D>
has been created using List.of()
, then it is unchangeable(*1), so it is okay to simply cast it to List<S>
, because nobody can actually add an S
among the D
s.
List.copyOf()
takes care of this decision logic for you.
(*1) when these lists were first introduced they were called "immutable"; later they realized that it is wrong to call them immutable, because a collection cannot be immutable, since it cannot vouch for the immutability of the elements that it contains; so they changed the documentation to call them "unmodifiable" instead; however, "unmodifiable" already had a meaning before these lists were introduced, and it meant "an unmodifiable to you view of my list which I am still free to mutate as I please, and the mutations will be very visible to you". So, neither immutable or unmodifiable is correct. I like to call them "superficially immutable" in the sense that they are not deeply immutable, but that may ruffle some feathers, so I just called them "unchangeable" as a compromise.