在Java中是否有类似于Enumerable.Range(x,y)的方法?

16

是否有类似于C#/.NET的

IEnumerable<int> range = Enumerable.Range(0, 100); //.NET

在Java中怎么做?

3个回答

21

在Java8以后,可以使用java.util.stream.IntStream.range(int startInclusive, int endExclusive)

Java8之前:

Java中没有这样的东西,但你可以像这样实现:

import java.util.Iterator;

public class Range implements Iterable<Integer> {
    private int min;
    private int count;

    public Range(int min, int count) {
        this.min = min;
        this.count = count;
    }

    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int cur = min;
            private int count = Range.this.count;
            public boolean hasNext() {
                return count != 0;
            }

            public Integer next() {
                count--;
                return cur++; // first return the cur, then increase it.
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}
例如,您可以通过以下方式使用Range:
public class TestRange {

    public static void main(String[] args) {
        for (int i : new Range(1, 10)) {
            System.out.println(i);
        }
    }

}

如果你不喜欢直接使用new Range(1, 10),你可以使用工厂类来实现:

public final class RangeFactory {
    public static Iterable<Integer> range(int a, int b) {
        return new Range(a, b);
    }
}

这里是我们的工厂测试:

public class TestRangeFactory {

    public static void main(String[] args) {
        for (int i : RangeFactory.range(1, 10)) {
            System.out.println(i);
        }
    }

}

干得好。找到一个旧问题并提供更好的答案。 :) - Kirk Woll
1
一个小的补充,next() 的契约是在迭代器没有更多元素时抛出 NoSuchElementException,因此我的建议是在 next() 中首先添加 if (!hasNext()) throw new NoSuchElementException()。 :) - Ibrahim Arief

3
Java中没有内置支持此功能的方法,但是很容易自己构建。Java API通常提供了所有所需的功能块,但不会使用开箱即用的方式组合它们。

Java采取的方法是认为有无限种组合方式,因此为什么要特别对待其中几种组合。有了正确的构建块,其他所有东西都可以轻松构建(这也是Unix哲学)。

其他语言API(例如C#和Python)采取了更谨慎的方法,它们确实选择了一些易于操作的事物,但仍允许更深奥的组合。

Java方法存在问题的典型示例可以在Java IO库中看到。创建文本输出文件的规范方法是:

BufferedWriter out = new BufferedWriter(new FileWriter("out.txt"));

Java IO库使用装饰器模式非常灵活,但更多时候你需要一个缓冲文件吧?与之对比的是Python中的等价物,它使典型用例变得非常简单:
out = file("out.txt","w")

是的,你说得对。只是想知道是否有内置的东西。 - Simon

2
您可以通过继承 ArrayList 来实现相同的功能:
public class Enumerable extends ArrayList<Integer> {   
   public Enumerable(int min, int max) {
     for (int i=min; i<=max; i++) {
       add(i);
     }
   }    
}

然后使用迭代器从最小值到最大值(包括最小值和最大值)获取整数序列。

编辑

正如sepp2k所提到的-上面的解决方案快速,简单实用,但有一些严重的问题(不仅空间复杂度为O(n),而应该是O(1))。为了更严格地模拟C#类,我宁愿编写一个自定义的Enumerable类来实现Iterable和自定义迭代器(但不是在这里和现在;))。


谢谢Andreas。那就没有了吗? - Simon
好的...请在您的答案中添加评论,这样我就可以点赞并将其标记为答案。 :) - Simon
5
请注意,这个解决方案实际上会占用与范围长度成比例的空间(不像 Enumerable.Range 仅存储起始值和结束值),对于大范围可能是不可接受的。 - sepp2k
还有许多缺点(我不会在自己的项目中使用那段代码),但是OP没有说明他为什么想要使用/模拟C#的Enumerable类型。更好的需求,更好的解决方案。 - Andreas Dolk
@sepp2k:不,内存使用仅被延迟。一旦您调用GetEnumerator或在foreach中使用它,IEnumerable将被实际值填充。MSDN文档:http://msdn.microsoft.com/en-us/library/system.linq.enumerable.range.aspx - Powerlord
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接