如何在Java 6中编写公共静态范围方法或范围类,以便它至少涵盖在其他编程语言中实现的常用功能?
如果您想回答这个问题,那么您可以忽略以下内容。
<小时/>
一次又一次,我错过了其他语言所具有的功能。对于我写的任何语言,我碰巧都有不同的编码风格,我不愿意改变这种习惯。所以,如果我想重用一种算法,我用不同的语言编写,那么我必须制作烦人的小黑客或变通办法来弥补缺失的功能。我想为range()
找到永久有效的解决方案。
对我来说 - range()
方法可能以惰性方式返回输入范围,并且它具有默认值。在任何时候它都有一个开始,一个结束的条件和一个获得下一个元素的方法。它应该在每个循环的中完美地工作。
我真的不想使用任何外部库,除了谷歌番石榴或类似的。相当于我的意思是经过适当测试的代码,使用JDK可以很好地工作,并且不被视为已弃用。
可能不清楚,所以:
How to write
我的意思是 - 你不必写它,只描述常见的陷阱以及推荐方法的优点和缺点。 loop code
,但也可以使用除了整数输入,这将是最常用的功能,我真的希望它适用于类BigInteger和Joda DateTime的类型实例。
for-each
循环作为一种方法,range()
标题可能如下所示:
/**TODO: Think about why / how to add step, limit, offset and cycle detection. */
public static <T extends Comparable<T>> Iterable<T> //
range(T from, Predicate<T> to, Function<T, T> fNext) //
throws NullPointerException, IllegalArgumentException {
作为个人偏好,我已将Range
编写为Builder模式实现。
范围实施Scala,Python 3,Groovy,.Net (with linq) [c#, f#, vb and c++],ruby,PHP ......所有这些都有所不同。< / p>
我不妨添加一个我想做的更好的例子(simple sample case)。
public static <T extends Comparable<T>> Iterable<T> //
range(T from, Predicate<T> to, Function<T, T> fNext) //
throws NullPointerException {
Preconditions.checkNotNull(from);
Preconditions.checkNotNull(to);
Preconditions.checkNotNull(fNext);
T current = from;
ArrayList<T> result = Lists.newArrayList();
if (to.apply(current)) result.add(current);
while (to.apply(current = Preconditions.checkNotNull(fNext.apply(current))))
result.add(current);
return result;
}
或懒惰的替代
//eats first element
public static <T extends Comparable<T>> Iterator<T> //
range2(final T from, final Predicate<T> to, final Function<T, T> fNext)
throws NullPointerException, UnsupportedOperationException {
Preconditions.checkNotNull(from);
Preconditions.checkNotNull(to);
Preconditions.checkNotNull(fNext);
return new Iterator<T>() {
T current = from;
@Override public boolean hasNext() {return to.apply(current);}
@Override public T next() {return current = Preconditions.checkNotNull(fNext.apply(current));}
@Override public void remove() {throw new UnsupportedOperationException();}
};
}
答案 0 :(得分:1)
痛点可能是必须为每种类型编写函数:
public static Function<Integer, Integer> intIncrementer(final int step) {
class IntIncrementer implements Function<Integer, Integer> {
private final int _step = step;
@Override public Integer apply(Integer i) {
return i + _step;
}
@Override public boolean equals(Object obj) {
return (obj instanceof IntIncrementer)
&& ((IntIncrementer) obj)._step == _step;
}
@Override public int hashCode() {
return _step;
}
}
return new IntIncrementer();
}
由于无法以通用方式表达i + _step
,因此您必须针对您希望支持的每种类型重新实现此功能(BigInteger
,long
等。)< / p>
我会质疑是否需要使用<T extends Comparable<T>>
而非<T>
。我认为施加这种限制没有任何好处。
与集合不同,Iterable类型不会强制equality contract。如果您希望能够比较范围而无需外部迭代其所有元素,那么返回定义此类合同的Range
类型可能会更好。
public interface Range<T> extends Iterable<T> {
// TODO: write the terms of the contract
@Override public boolean equals(Object obj);
@Override public int hashCode();
// TODO: other useful methods?
}
当涉及到原语时,创建包装器对象会产生开销。与仅使用传统的递增for
循环相比,这可能在大范围内效率显着降低。
答案 1 :(得分:0)
我会选择最近的路径。创建一个这样的界面:
interface Steppable<T>{
T defaultStep(); //Returns 1 for most number types
T value(); //Returns the value itself
Steppable<T> step(T amount); //the stepping logic
}
为范围函数(整数,长整数,日期等)中我想要使用的每种类型编写一大堆接口实现。然后为每个可行类型创建一个重载的range()
函数,以便于使用。
我会采用这种方法,因为它可以直接添加更多可行的类型。至于缺点,这种方法有点冗长。