import java.util.NoSuchElementException;
import java.util.Iterator;
public class Range implements Iterable<Integer> {
private int start, end;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
public Iterator<Integer> iterator() {
return new RangeIterator();
}
// Inner class example
private class RangeIterator implements
Iterator<Integer> {
private int cursor;
public RangeIterator() {
this.cursor = Range.this.start;
}
public boolean hasNext() {
return this.cursor < Range.this.end;
}
public Integer next() {
if(this.hasNext()) {
int current = cursor;
cursor ++;
return current;
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public static void main(String[] args) {
Range range = new Range(1, 10);
// Long way
Iterator<Integer> it = range.iterator();
while(it.hasNext()) {
int cur = it.next();
System.out.println(cur);
}
// Shorter, nicer way:
// Read ":" as "in"
for(Integer cur : range) {
System.out.println(cur);
}
}
}
#1 楼
变量我理解为什么要使用
Range.this.end
和Range.this.start
以避免混淆那些变量的来源...如果您需要Range.this
作为教学练习的一部分,那么可以肯定。否则,我会建议三件事。...添加
range
作为前缀,即使它有点多余使它们成为最终的...
每行变量...(使版本控制差异/补丁更易于阅读)
代码如下:
private final int rangeStart;
private final int rangeEnd;
然后,所有
Range.this.start
都只是rangeStart
等。嵌套类
您的迭代器类是非静态类,因此它可以引用外部类的范围开始end。
在这种情况下,可以很容易地将嵌套类更改为静态类。这有可能简化内存管理,因为迭代器不需要引用封闭的范围。
考虑一个私有静态迭代器实例:
// Inner class example
private static final class RangeIterator implements
Iterator<Integer> {
private int cursor;
private final int end;
public RangeIterator(int start, int end) {
this.cursor = start;
this.end = end;
}
public boolean hasNext() {
return this.cursor < end;
}
public Integer next() {
if(this.hasNext()) {
int current = cursor;
cursor ++;
return current;
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
此静态类完全不需要使用对
Range.this
的反向引用。 > 预验证
最好预先验证状态,而不是陷入错误...此代码: >
public Iterator<Integer> iterator() {
return new RangeIterator(start, end);
}
会更好一些:简化为:
public Integer next() {
if(this.hasNext()) {
int current = cursor;
cursor ++;
return current;
}
throw new NoSuchElementException();
}
到正好:想象这是一种教育策略。
以整数为例
由于int自动合并,我担心Integer可能不是数据类型的正确选择。您可能希望将非原始数据作为数据。
自动装箱会引起混淆。
结论
我对问题的看法不多。
评论
\ $ \ begingroup \ $
谢谢。我没想到要使用final,这是个好主意。我也同意私有的静态类要比内部类好,但是我忘了提到代码是为了向他们提供内部类的示例,以供进一步了解。后增量是为了避免混淆而进行的更长的方法,因为学生们发现它令人困惑。关于使用非原始类型的有趣观点。为了简单起见,我想提供一个不是容器(例如,链表,哈希集等)的可迭代的示例。您能想到一个不使用原语的东西吗?
\ $ \ endgroup \ $
– Sahand
2014年4月25日下午5:55
\ $ \ begingroup \ $
关于“ Pre-Validate”的要点,要加上一些措辞:这个惯用法被称为“保护条款”(c2.com/cgi/wiki?
\ $ \ endgroup \ $
–mdo
2014年4月25日在6:20
#2 楼
总体而言,这是值得学习的很好的代码。功能性
我喜欢您分别对下限和上限使用了包容性-排他性约定。该设计的基本原理将是一个有趣的讨论主题。
为了方便起见,我建议添加第二个构造函数:
public Range(int end) {
this(0, end);
}
start()
和end()
的吸气剂。从技术上讲,您也应该覆盖.equals()
和.hashCode()
,但为简单起见也可以忽略它们。做个好习惯。它还可以帮助学生了解哪些方法是界面的强制性部分(嗯,实际上是所有方法)。JavaDoc将是一个很好的教学习惯。至少要记录外部类和内部类,并可能还要记录它们的构造函数。它们看起来不太像那种函数调用。
将
@Override
和if
声明为for
可以帮助向学生强调while
是不可变的,只有start
会改变状态。也许添加end
可以减轻@rolfl对涉及final
和Range
的内部类的担忧。 /> …虽然我能理解您是否选择不让学生负担那琐事。独立保持状态。也许这可能是一个很好的例子?
@Override
public Integer next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
// The post-increment magically takes effect _after_
// returning. This is equivalent to
//
// int value = this.cursor++;
// return value;
//
return this.cursor++;
}
#3 楼
@rolfl完全钉住了它。只剩下一些挑剔的人了:我会丢弃所有无意义的注释,除非它们在您教此时有目的。 IDE
每当可以从
@Override
放下this.
时,我都会放下它。使用您的IDE的重新格式化功能(相当于Eclipse中的this.cursor
)我认为在向您的班级提出问题之前先问一个好主意!
评论
\ $ \ begingroup \ $
在这里发表评论是因为您提到...评论:我个人更喜欢多行评论,而不是// —并且在我的代码库中,我至少坚持一个类级别的Javadoc(无论如何,Range概念是什么?)
\ $ \ endgroup \ $
–mdo
2014年4月25日在6:27
\ $ \ begingroup \ $
和@Override不仅具有可读性,因为它可以确保正确的覆盖和编译错误
\ $ \ endgroup \ $
–mdo
2014年4月25日在6:29
#4 楼
我认为有些学生会喜欢没有内部类的示例:范围可以在没有内部类的情况下实现Iterator。您只需要将光标重置为起始值即可。在这里,我完成了对范围的迭代之后,在Iterator方法和下一个方法中重置了游标。它适用于建议的示例。当然,迭代器并不能保持状态独立,也不能用于更复杂的示例,但是我不需要将构造函数参数传递给内部类。
import java.util.NoSuchElementException;
import java.util.Iterator;
public class Range implements Iterable<Integer>, Iterator<Integer> {
private int start, end, cursor;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
public Iterator<Integer> iterator() {
cursor = start;
return this;
}
public boolean hasNext() {
return cursor < end;
}
public Integer next() {
if(!hasNext()) {
cursor = start;
throw new NoSuchElementException();
}
return cursor++;
}
public void remove() {
throw new UnsupportedOperationException();
}
public static void main(String[] args) {
Range range = new Range(1, 10);
// Long way
Iterator<Integer> it = range.iterator();
while(it.hasNext()) {
int cur = it.next();
System.out.println(cur);
}
// Shorter, nicer way:
// Read ":" as "in"
for(Integer cur : range) {
System.out.println(cur);
}
Range digits = new Range(0, 10);
for (Integer tensDigit : digits) {
for (Integer onesDigit : digits) {
System.out.format("%s%s ", tensDigit, onesDigit);
}
System.out.println();
}
}
}
>#5 楼
可以使用匿名类编写iterator
方法,该类直接访问其工作所需的属性。@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int cursor = start;
@Override
public boolean hasNext() {
return cursor < end;
}
@Override
public Integer next() {
if (! hasNext()) {
throw new NoSuchElementException();
}
return cursor++;
}
};
,通常需要使用匿名/内部/单独的类。
评论
如何@override注释?本文可能会有所帮助:yegor256.com/2015/04/30/iterating-adapter.html