使用Guava的
然而,通常情况下我得到的是
显然,由于类型擦除,Guava无法直接解决这个问题:
假设我有像
但是这暴露了一些丑陋的强制类型转换操作。
作为替代,我可以提供一个
但实际上该列表并没有被过滤,对于那些无法转换或强制转换为
第二种解决方案对我来说更加聪明。要定义的
剩下的问题是: 是否有更聪明的方法可以通过单个步骤执行必要的转换和过滤?我可以简单地定义一些实用函数,例如:
第二个函数是第一个函数的简化版,使用
但是也值得拥有第一个函数,因为谓词不一定是
想象一下一个
filter(Iterable<?> unfiltered, Class<T> type)
方法可以轻松地过滤列表或可迭代对象。此操作执行两个任务:过滤列表并将其转换为给定类型T的序列。然而,通常情况下我得到的是
Iterables<Something<?>>
,我想要获取一些专门的T的子序列Iterables<Something<T>>
。显然,由于类型擦除,Guava无法直接解决这个问题:
Something<T>
没有提供任何关于它的T的直接信息。假设我有像
S<? extends Number>
这样的东西。如果我能定义一些谓词来告诉我S<?>
是否可以强制转换为S<Double>
,那么我就可以将其用作过滤器。<T extends Number> Predicate<S<?>> isOfType(Class<N> type) {...}
使用:
Iterable<S<?>> numbers;
Iterable<S<?>> filtered = Iterable.filter(numbers, isOfType(Double.class));
这个执行筛选任务,但缺失转换步骤。如果我认为我的谓词很好用,我甚至可以考虑强制转换:
Iterable<S<Double>> doubles = (Iterable<S<Double>>) filtered;
但是这暴露了一些丑陋的强制类型转换操作。
作为替代,我可以提供一个
Function<S<?>, S<Double>>
来执行转换。与Class.cast()
相比,它不应该抛出ClassCastException
,而是在元素无法转换(或转换失败)时简单地返回null
。这样,序列可以在没有任何显式转换的情况下进行转换:<T extends Number> Function<S<?>, S<T>> castOrNull(Class<N> type) {...}
Iterable<S<Double>> doubles = Iterable.filter(numbers, castOrNull(Double.class));
但实际上该列表并没有被过滤,对于那些无法转换或强制转换为
S<Double>
的每个元素,它仍然包含空对象。
但可以通过一个额外的过滤步骤轻松解决这个问题,例如:Iterable<S<Double>> doubles = Iterables.filter(doubles, Predicates.notNull());
第二种解决方案对我来说更加聪明。要定义的
Function
可能执行转换(隐藏未经检查的操作),也可能在必要时创建一些新的对象S<T>
。剩下的问题是: 是否有更聪明的方法可以通过单个步骤执行必要的转换和过滤?我可以简单地定义一些实用函数,例如:
<I,O> Iterables<O> convert(
Iterables<O> input,
Function<? super I, ? extends O> convert,
Predicate<? super O> filter);
<I,O> Iterables<O> convert(
Iterables<O> input,
Function<? super I, ? extends O> convert);
第二个函数是第一个函数的简化版,使用
Predicates.notNull()
;但是也值得拥有第一个函数,因为谓词不一定是
Predicates.notNull()
。想象一下一个
Iterable<Iterable<? extends Number>>
。转换函数 Function<Iterable<? extends Number>, Iterable<Double>>
可以简单地返回一个过滤后的序列,该序列可能为空,而不是返回 null。最终,通过使用 Iterables.isEmpty()
,额外的过滤器可以删除空序列。
Iterable.filter(...)
返回一个带有扩展功能的可迭代对象,以便您可以链接过滤器,那将非常有用。/* S extends Collection */ Iterable<S<Double>> doubles = Iterable.filter(numbers, castOrNull(Double.class)).filter(Predicates.notNull()).filter(Predicates.notEmpty());
- aalku