【问题标题】:Java Iterator for primitive types原始类型的 Java 迭代器
【发布时间】:2013-04-03 15:11:16
【问题描述】:

我有一个如下形式的 Java 类:

class Example {

  private byte[][] data;

  public Example(int s) { data = new byte[s][s]; }

  public byte getter(int x, int y)         { return byte[x][y]; }
  public void setter(int x, int y, byte z) { byte[x][y] = z;    }
}

我希望能够使用这样的迭代器从外部迭代私有数据:

for(byte b : Example) { ;/* do stuff */ }

我尝试实现一个私有 Iterator 类,但遇到了问题:

private class ExampleIterator implements Iterator {
  private int curr_x;
  private int curr_y;

  public ExampleIterator() { curr_x=0; curr_y=-1; }
  public boolean hasNext() { 
    return curr_x != field.length-1
        && curr_y != field.length-1; //is not the last cell?
  }
  public byte next() { // <-- Error is here: 
                       // Wants to change return type to Object
                       // Won't compile!
    if(curr_y=field.length) { ++curr_x; curr_y=0; }
    return field[curr_x][curr_y];
  }
  public void remove() { ; } //does nothing
}

如何为原始类型(不是泛型)实现 external 迭代器?这在 Java 中可行吗?

【问题讨论】:

    标签: java iterator primitive private-members autoboxing


    【解决方案1】:

    迭代器不能产生原始类型的值。但是,它可以产生包装类型Byte 的值。此类值可以将auto-unboxed 转换为byte(只要它们不是null)。

    private class ExampleIterator implements Iterator<Byte> {
      public boolean hasNext() { ... }
      public Byte next() { ... }
    }
    

    那么你可以这样使用它:

    for (byte b : example) { ... }
    

    【讨论】:

    • 我不熟悉自动(取消)装箱的概念。这就是我的困惑的根源和解决方案的来源。
    • 通常像这样的自动装箱是一种快速生成大量垃圾的方法。但是,对于Byte,我相信大多数Java 实现都使用享元模式(因为只有256 个byte 值),因此GC 没有额外负担。但是请注意,您必须使用for (byte b : instanceOfExample)——您不能遍历一个类。
    • @TedHopp 感谢您的技术洞察力,知道“幕后”发生的事情总是很有价值!
    【解决方案2】:

    Java 8 引入了primitive iterators,它允许您在迭代 int、long 和 double 集合时避免装箱/拆箱。

    您可以创建自己的 PrimitiveIteratorbyte,并以类型安全的方式实现泛型 PrimitiveIterator&lt;Byte,ByteConsumer&gt;ByteConsumer 也将被实施。两者都很简单。

    为什么jdk中没有PrimitiveIterator.ofByte?可能是因为机器字长,通常不小于 int。或者字节迭代器最好由流等完成。

    【讨论】:

    • 原始类型有类似的Iterable,所以我可以做for(double d : myContainerWithDoubles) {} 吗?
    • 没有 for-each 原始迭代器。最佳匹配是实现 PrimitiveIterator.OfDouble 并以功能方式使用它。
    【解决方案3】:

    您不能将泛型与基元一起使用,因为泛型需要该类型的类。

    您可以做的是遍历 Wrapper 类型(整数、字节、布尔值等)...

    【讨论】:

      【解决方案4】:

      实现Iterable,并返回一个字节对象而不是一个字节原语:

      class Example implements Iterable<Byte> {
      
      ..
      
          public Iterator<Byte> iterator() {
              return new MyIterator();
          }
      
          private class MyIterator implements Iterator<Byte> {
              public Byte next() {...}
              ....
          }
      }
      

      实现 Iterable 而不是 Iterator 允许您使用 for-each 循环直接循环对象项。

      【讨论】:

        【解决方案5】:

        如果你想让你的迭代器实现 java.util.Iterator 那么 next() 将不得不返回 Byte

        class ByteArrayIterator implements Iterator<Byte> {
            final byte[] a; 
            int i = 0;
            ByteArrayIterator(byte[] a) {
                this.a = a; 
            }
        
            public boolean hasNext() {
                return i < a.length;
            }
        
            public Byte next() {
                if (i == a.length) {
                    throw new NoSuchElementException();
                }
                return a[i++];
            }
        
            public void remove() {
                throw new UnsupportedOperationException();
            }
        }
        

        remove 也可以实现。如果你不需要它实现 Iterator 那么我们可以改变 next() 来返回字节

            class ByteArrayIterator {
        ...
            public byte next() {
                    if (i == a.length) {
                        throw new NoSuchElementException();
                    }
                    return a[i++];
                }
        

        【讨论】:

          猜你喜欢
          • 2018-10-16
          • 1970-01-01
          • 2015-08-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多