java的集合框架里没有range这个东西,大家都习惯于用三段式的for,鄙人用过其他的语言,觉得range确实是个不错的东西。 当然这个实现起来一点也不难,创建个list或array就行了,不过本文讲得是使用java8的stream。 为什么用stream呢,一是赶潮流,java8已经提供了部分函数式语言特征,stream就是这个部分中的重要一点,二是有一种懒加载的stream,使用list会使用大量内存,这个不需要,就跟三段式for一样多的内存就行(应该消耗大些,毕竟有个数据结构)。
我们先来了解stream,没有了解过java8的可能以为我说的这个stream是指io流,但这里的stream是java8提供的一种新的集合框架,有点类似于iterable,不过它的使用方式比较函数化,迭代操作不是使用传统或增强for,而是提供方法:例如forEach,方法接受的是函数式接口。 stream的创建不谈很多,就提出本文中需要的那个,Stream.generate(Supplier<T> s)这个方法 Supplier<T> 是个泛型接口,这个接口只有一个抽象方法(因为java8中接口允许有default方法,所以这里要强调是抽象方法),T get()。现在来写我们的range:
public class Range {
public static Stream<Long> range(final long start,long length,int step) {
Supplier<Long> seed = new Supplier<Long>() {
private long next = start;
@Override
public Long get() {
long _next = next;
next += step;
return _next;
}
};
return Stream.generate(seed).limit(length);
}
public static void main(String[] args) {
range(1,10,2).forEach(num -> {
System.out.println(num);
});
}
}
range完成,经过测试,确实是懒加载的,注意我这里提供的第二个参数是长度,而不是end,这样少了很多判断(这些烦琐事交给别人),不过这里有个缺点,就是我们不能使用for循环,如果要使用就要将stream转换成collection,我没测试,但我估计这样就没有了懒加载。其实要实现可以进行增强for循环的range,应该实现一个iterable接口就行,这里扔以Stream为基础建立。
先放上代码吧。
public class Range implements Iterable<Long> {
private Stream<Long> range;
public Range(final long start,final long length,final int step) {
Supplier<Long> seed = new Supplier<Long>() {
private long next = start;
@Override
public Long get() {
long _next = next;
next += step;
//System.out.println("get:"+next);
return _next;
}
};
range = Stream.generate(seed).limit(length);
}
public static void main(String[] args) {
for (long next:new Range(1,10,1)){
System.out.println(next);
}
}
@Override
public Iterator<Long> iterator() {
return range.iterator();
}
}
这里不再采用静态的方法去生成range。让Range类实现一个Iterable接口,因为这个接口只需要实现一个iterator方法,而Stream有一个默认方法iterator,经过测试这个也是懒加载形式,而且java8中为Iterable接口提供了默认的forEach方法,也就可以使用函数式了。当然我们可以自己去覆盖这个forEach, 直接使用stream的也行。注意覆盖接口中的默认方法,需要显示的写@Override,这里也倡导大家覆盖方法都写上这个annotation