Фильтрующие списки универсальных типов

Списки или Iterables могут быть легко отфильтрованы с помощью фильтра guavas (Iterable > Нефильтрованный, тип Class ) . Эта операция выполняет две задачи: список фильтруется и преобразуется в последовательность заданного типа T.

Однако довольно часто я получаю Iterables > и я хочу получить подпоследовательность Iterables > для некоторого специализированного T.

Ясно, что Guava не может решить эту проблему из коробки из-за стирания типа: Что-то не предоставляет никакой прямой информации о своем T.

Допустим, у меня есть что-то вроде S расширяет Number> . Если я могу определить какой-то предикат, который сообщает мне, может ли S > быть приведен к S , я могу использовать его как фильтр:

 Predicate> isOfType(Class type) {...}

с:

Iterable> numbers;
Iterable> filtered = Iterable.filter(numbers, isOfType(Double.class));

Это выполняет задачу фильтрации, но пропускает этап преобразования. Если я думаю, что мой предикат работает хорошо, я могу даже подумать о приведении:

Iterable> doubles = (Iterable>) filtered;

Но это открывает некоторую уродливую операцию приведения.

В качестве альтернативы я могу предоставить Function , S > для выполнения гипса. В отличие от Class.cast () , однако, он не должен вызывать исключение ClassCastException , а просто возвращать null , если элемент не может быть приведен (или преобразован). Таким образом, последовательность может быть преобразована без явного приведения:

 Function, S> castOrNull(Class type) {...}

Iterable> doubles = Iterable.filter(numbers, castOrNull(Double.class));

Но список на самом деле не фильтруется: вместо этого он по-прежнему содержит нулевые объекты для каждого элемента, который не может быть преобразован или преобразован в S . Но это можно легко решить с помощью дополнительного шага фильтрации, например:

Iterable> doubles = Iterables.filter(doubles, Predicates.notNull());

Второе решение кажется мне намного умнее. Функция , которая должна быть определена, может либо выполнить приведение (которое скрывает непроверенную операцию), либо действительно может создать новый объект S , если необходимо.

Остающийся вопрос является: Есть ли более разумный способ выполнить необходимое преобразование и фильтрацию за один шаг? Я могу просто определить некоторую служебную функцию, например:

 Iterables convert(
    Iterables input, 
    Function convert, 
    Predicate filter);

 Iterables convert(
    Iterables input, 
    Function convert);

Где вторая функция является сокращением первой с Predicates.notNull () ;

Но стоит иметь первую функцию, тоже, поскольку предикат не нужен Predicates.notNull () .

Представьте себе Iterable > . Функция конвертера Function , Iterable > может просто возвращать отфильтрованную последовательность, которая может быть пустой, вместо возврата null. Дополнительный фильтр может окончательно отбросить пустые последовательности с помощью Iterables.isEmpty () .

19
задан tshepang 16 June 2014 в 21:29
поделиться