Списки или 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 super I, ? extends O> convert,
Predicate super O> filter);
Iterables convert(
Iterables input,
Function super I, ? extends O> convert);
Где вторая функция является сокращением первой с Predicates.notNull ()
;
Но стоит иметь первую функцию, тоже, поскольку предикат не нужен Predicates.notNull ()
.
Представьте себе Iterable
. Функция конвертера Function
может просто возвращать отфильтрованную последовательность, которая может быть пустой, вместо возврата null. Дополнительный фильтр может окончательно отбросить пустые последовательности с помощью Iterables.isEmpty ()
.