one*_*one 9 java generics programming-languages functional-programming
我正在尝试为Java创建一个小函数式编程库(只是为了抓住我自己的痒).在为s,s和s 定义高阶函数时List
,我遇到了这个问题:采用集合并返回相同类型集合的函数具有几乎相同的实现,但必须为每个函数重新定义数据结构 - s,s和s.Set
Map
List
Set
Map
例如,这里是s和s 的map
函数的实现:List
Set
public static <A, B> List<B> map(
List<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
List<B> ys = new ArrayList<B>();
for(A a : xs) {
ys.add(transformer.apply(a));
}
return ys;
}
public static <A, B> Set<B> map(
Set<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
Set<B> ys = new HashSet<B>();
for(A a : xs) {
ys.add(transformer.apply(a));
}
return ys;
}
Run Code Online (Sandbox Code Playgroud)
一个filter
函数:
public static <A> List<A> filter(
List<? extends A> xs,
Func1<? super A, Boolean> predicate
) {
List<A> ys = new ArrayList<A>();
for(A a : xs) {
if(predicate.apply(a)) {
ys.add(a);
}
}
return ys;
}
public static <A> Set<A> filter(
Set<? extends A> xs,
Func1<? super A, Boolean> predicate
) {
Set<A> ys = new HashSet<A>();
for(A a : xs) {
if(predicate.apply(a)) {
ys.add(a);
}
}
return ys;
}
Run Code Online (Sandbox Code Playgroud)
从该示例可以看出,实现的主体Set
和List
几乎相同.
有喜欢很多很多的功能map
,并filter
在我的图书馆,而且每个是针对每一类藏品我感兴趣的三次定义(即List
,Set
和Map
).这会导致很多代码重复和代码异味.我想知道Java中是否有某种方法可以帮助我避免所有的代码重复.
任何帮助将不胜感激.谢谢.
编辑:
Func1
是一个定义为的接口:
interface Func1<A, B> {
public B apply(A a);
}
Run Code Online (Sandbox Code Playgroud)
public static <A, B> List<B> map(
List<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
List<B> ys = new ArrayList<B>();
map(xy, transformer, ys);
return ys;
}
public static <A, B> Set<B> map(
Set<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
Set<B> ys = new HashSet<B>();
map(xy, transformer, ys);
return ys;
}
private static <A, B> map(
Collection<? extends A> xs,
Func1<? super A, ? extends B> transformer,
Iterable<B> ys
) {
for(A a : xs) {
ys.add(transformer.apply(a));
}
}
Run Code Online (Sandbox Code Playgroud)
任务完成.
注意,这是典型的Java API,要将集合中的mutable传递给它,而不是在方法中创建一个新的.就个人而言,我不是集合级别的可变性的粉丝,但它是我们必须使用的(在Java中).
(我不喜欢A
和B
作为这类东西的通用参数.)
或者你可以使用工厂:
public static <A, B> List<B> map(
List<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
return map(xs, transformer, new CollectionFactory<B, List<B>>() {
public List<B> create() { return new ArrayList<B>(); }
});
}
public static <A, B> Set<B> map(
Set<? extends A> xs,
Func1<? super A, ? extends B> transformer
) {
return map(xs, transformer, new CollectionFactory<B, Set<B>>() {
public Set<B> create() { return new HashSet<B>(); }
});
}
private interface CollectionFactory<E, C extends Collection<E>> {
C create();
}
private static <A, B, C extends Collection<B>> C map(
Iterable<? extends A> xs,
Func1<? super A, ? extends B> transformer,
CollectionFactory<B, C> factory
) {
C ys = factory.create();
for(A a : xs) {
ys.add(transformer.apply(a));
}
return ys;
}
Run Code Online (Sandbox Code Playgroud)
(如果你能忍受匿名内部类的毫无意义的冗长.)
如果它不适合Collection
那么你需要放一些(丑陋的)适配器.
为了完整性(虽然未经过测试,可以进行一些调整),使用继承的令人不快的解决方案:
Set<String> strs = hashSets().map(things, formatter);
...
public static <E> Functions<E, Set<E>> hashSets() {
return new Functions<E, Set<E>>() {
protected Set<E> createCollections() {
return new HashSet<E>();
}
};
}
public abstract class Functions<E, C extends Collection<E>> {
protected abstract C createCollection();
public <S> C map(
Set<? extends S> xs,
Func1<? super S, ? extends E> transformer
) {
C ys = createCollection();
for(S a : xs) {
ys.add(transformer.apply(a));
}
return ys;
}
public <S> C filter(
List<? extends S> xs,
Func1<? super S, Boolean> predicate // Predicate<? super S> might be nicer!!
) {
C ys = createCollection();
for(A a : xs) {
if(predicate.apply(a)) {
ys.add(a);
}
}
return ys;
}
}
Run Code Online (Sandbox Code Playgroud)
Java 没有高阶多态性(又名高阶多态性),因此这在类型系统中是不可能的。许多Java 程序员求助于XML 和/或反射(即转义类型系统)来解决这一缺陷。
Scala 可以处理这个问题,您所描述的称为协变函子。这种相当基本的数据类型(以及更多)已在 Scalaz 库中实现,并包括 java.util.* 的实现。
此外,还有更多的协变函子不是集合,还有更多的函子不是协变的。
如果您想进一步探索这个特定的概念,您可能希望在 google 上搜索“20 个中级 Scala 练习”。
归档时间: |
|
查看次数: |
635 次 |
最近记录: |