Цепочка операций Stream над общими типами приводит к ошибкам типа - PullRequest
0 голосов
/ 21 октября 2018

Следующие классы и методы:

class A<T extends B> { }
class B {}

Stream<A<? extends B>> find() {
    return findAll()                        // Stream<Optional<A<? extends B>>>
            .filter(Optional::isPresent)    // Stream<Optional<A<? extends B>>>
            .map(Optional::get)             // Stream<A<capture of ? extends B>>
            .filter(a -> false);            // Stream<A<capture of ? extends B>>
}

Stream<Optional<A<? extends B>>> findAll() {
    return Stream.empty();
}

Скомпилировать нормально с javac, но привести к ошибкам типа в IDEA: screenshot

Ошибки исчезают, когдаЯ либо

  • Удалить filter(Optional::isPresent()).map(Optional::get) пару
  • Удалить окончательный filter вызов

Я не могу понять это.Это ошибка IDEA?

Редактировать: Некоторые новые идеи благодаря LuCio:

  1. Хотя моя версия javac (10.0.2) делаетне жалуйтесь, другие версии javac и IDE делают, так что это не ошибка IDEA

  2. Разделение выражения на две части и предоставление промежуточному значению явного типа помогает:

    Stream<A<? extends B>> aStream = findAll()
            .filter(Optional::isPresent)
            .map(Optional::get);
    return aStream
            .filter(a -> false);
    

    (обратите внимание, что тип IDEA для aStream означает Stream<? extends A<? extends B>>, хотя он просто принимает присвоение этому типу)

Таким образом, возникает вопрос: почему промежуточный типтак оно и есть, и почему это нормально - просто игнорировать его, присваивая другой тип?

1 Ответ

0 голосов
/ 08 февраля 2019

Это потому, что Stream.map имеет следующую подпись:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

В этом случае R равно A<? extends B>.Следовательно, возвращаемое значение функции неявно

? extends A<? extends B>

В этот момент я полагаю на этот вопрос в некоторой степени отвечает

Является ли List подклассом List ?Почему дженерики Java не являются неявно полиморфными?

Это можно сделать для удобной компиляции, либо изменив тип возвращаемого значения:

<T extends B> Stream<? extends A<? extends B>> find() {
    return findAll()                        // Stream<Optional<A<? extends B>>>
      .map(Optional::get)             // Stream<A<capture of ? extends B>>
      .filter(a -> false);            // Stream<A<capture of ? extends B>>
}

, либо приведя функцию к явному возвращению A<? extends B>:

<T extends B> Stream<A<? extends B>> find() {
    return findAll()
      .map((Function<Optional<A<? extends B>>, A<? extends B>>) Optional::get)
      .filter(a -> false);
}

Для пояснения, Stream<C>, где C extends A<B>, само по себе не является Stream<A<? extends B>>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...