Почему "Stream.collect" безопасен по типу и "Stream.toArray" (IntFunction <a []>) `is not?

Рассмотрим следующий фрагмент кода

String strings[] = {"test"};
final List<String> collect = java.util.Arrays.stream(strings).collect(java.util.stream.Collectors.toList());
final Double[] array = java.util.Arrays.stream(strings).toArray(Double[]::new);

Почему Java может гарантировать правильный тип в случае сбора (изменение универсального типа сбора на, например, Double приводит к ошибке времени компиляции), но не в случае массива (прекрасно компилируется, несмотря на apply(int) из Double[]::new дает Double[], а не Object[], но выдает ArrayStoreException если используется неправильно, как указано выше)?

Каков наилучший способ генерировать ошибку времени компиляции в случае, если я изменю тип потока, не изменяя данную IntFunction в вызове toArray?

Ответ 1

Сигнатура метода Stream::toArray выглядит следующим образом. Обратите внимание, что параметры типа T и A совершенно не связаны.

public interface Stream<T> {
    <A> A[] toArray(IntFunction<A[]> generator);
}

В источнике ReferencePipeline.java вы можете найти следующий комментарий:

Поскольку A имеет никакого отношения к U (невозможно объявить, что A является верхней границей U), статической проверки типов не будет. Поэтому используйте необработанный тип и примите A == U вместо того, чтобы распространять разделение A и U всей базе кода. Тип времени выполнения U никогда не проверяется на равенство с типом компонента типа времени выполнения A[]. Проверка времени выполнения будет выполняться, когда элемент хранится в A[], поэтому, если A не является ArrayStoreException U будет ArrayStoreException.