Замените беглые итерации из гуавы потоками - PullRequest
2 голосов
/ 27 мая 2019

У меня есть метод для фильтра по типу, он получает в качестве входных данных Collection<?> collection и Class<T> tClass.Я хочу заменить FluentIterable на Stream.

public static <T> List<T> filterByType(final Collection<?> filerCollection, final Class<T> classType) 
{
    return FluentIterable.from(filerCollection).filter(classType).toList();
}

. Я попытался с помощью этого решения:

public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
    return (List<T>) filter.stream()
            .filter(Objects::nonNull)
            .map(Object.class::cast)
            .collect(Collectors.toList());
}

как это сделать без приведения возврата Stream?

Ответы [ 4 ]

4 голосов
/ 28 мая 2019

Вы забыли проверить, являются ли ваши элементы даже типа T. То есть сначала вы должны отфильтровать эти элементы:

return filter.stream()
             .filter(classType::isInstance) // only keep elements of type T
             .map(classType::cast)          // safely cast from Object to T
             .collect(Collectors.toList()); // collect into a List<T>

Class#isInstance() также непосредственно заботится о null значениях, поэтому вам не нужно использовать filter(Object::nonNull).

1 голос
/ 28 мая 2019

Посмотрите внимательно, что делает FluentIterable::filter(Class<T>), и сравните его с картами каждого предмета с classType с кастингом. Ваше намерение состоит в том, чтобы отфильтровать эти элементы classType.

Затем вместо Object.class::cast следует использовать classType::cast, поскольку требуемый класс уже передан через Class<T> classType и может использоваться непосредственно в качестве ссылки на метод. Object.class::cast приводит к родительскому элементу Object, от которого наследуется каждый объект.

Вот что вы хотите:

public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
    return filter.stream()
        .filter(Objects::nonNull)
        .filter(item -> item.getClass().equals(classType))
        .map(classType::cast)
        .collect(Collectors.toList());
}

Редактировать: Как уже упоминалось в другом ответе , можно также использовать filter(classType::isInstance).

1 голос
/ 28 мая 2019

Вы должны использовать classType::cast, потому что здесь вы используете Object.class::cast, что в основном делает ничего

public static <T> List<T> typeFilter(final Collection<?> filter, final Class<T> classType) {
    return filter.stream()
                 .filter(Objects::nonNull)
                 .map(classType::cast)
                 .collect(Collectors.toList());
}

И чтобы быть еще лучше, добавьте filter(classType::isInstance) к вашемуметод цепочки

0 голосов
/ 29 мая 2019

Другая вещь, которую вы можете сделать (хотя это, вероятно, немного менее эффективно, чем сделать это в два шага), это определить что-то вроде этого:

public static <T> Function<Object, Stream<T>> instancesOf(Class<T> c) {
  return o -> c.isInstance(o) ? Stream.of(c.cast(o)) : Stream.empty();
}

, а затем использовать это так:

return filter.stream()
    .flatMap(instancesOf(classType))
    .collect(toList());
...