一个迭代并返回相同对象的迭代器.不好的做法?

Bri*_*ris 9 java iterator guava

我正在编写GC友好代码来读取并向用户返回一系列byte[]消息.在内部我重复使用ByteBuffer它,这意味着我将在大多数时间重复返回相同的byte[]实例.

我正在考虑编写警示javadoc并将其暴露给用户作为Iterator<byte[]>.AFAIK它不会违反Iterator合同,但如果他们这样做Lists.newArrayList(myIterator)并且在每个位置回到List人口中,那么用户肯定会感到惊讶byte[]!

问题:对于可能变异并返回相同对象来实现接口的类,这是不好的做法吗?Iterator

  • 如果是这样,最好的选择是什么?"不要改变/重用你的对象"是一个简单的答案.但它没有解决重用非常需要的情况.

  • 如果没有,你如何证明违反最不惊讶原则

两个小调:

  • 我正在使用Guava,AbstractIterator因此remove()并不是真正值得关注的问题.

  • 在我的用例中,用户就是,这个类的可见性将受到限制,但我已经尝试过这个问题,通常可以更广泛地应用.

更新:我接受路易斯的答案,因为它的票数比基思多3倍,但请注意,在我的用例中,我打算采用我留下的代码来评论基思对生产的回答.

Lou*_*man 10

EnumMap在它的entrySet()迭代器中基本上完成了这一点,这导致了令人困惑,疯狂,令人沮丧的错误.

如果我是你,我就不会使用Iterator- 我会写一个不同的API(可能与Iterator完全不同,甚至)并实现它.例如,你可以写一个新的API,如需要输入ByteBuffer写的留言到,因此API的用户可以控制的缓冲区是否得到重用.这似乎相当直观(用户可以编写明显且干净地重用的ByteBuffer代码),而不会产生不必要的混乱代码.


Kei*_*all 7

我会定义一个你可以无效的中间对象.所以你的函数会返回一个Iterator<ByteArray>,ByteArray就像这样:

class ByteArray {
    private byte[] data;
    ByteArray(byte[] d) { data = d; }
    byte[] getData() {
        if (data == null) throw new BadUseOfIteratorException();
        return data;
    }
    void invalidate() { data = null; }
}
Run Code Online (Sandbox Code Playgroud)

然后,您的迭代器可以使之前返回的无效,ByteArray以便将来的任何访问(通过getData您提供的任何其他访问者)都将失败.然后,至少如果某人做了类似的事情Lists.newArrayList(myIterator),他们至少会得到一个错误(当ByteArray访问第一个无效时),而不是静默地返回错误的数据.

当然,这不会捕获所有可能的不良用途,但可能是常见的用途.如果您对永远不会返回原始数据byte[]并提供类似的访问器感到满意byte get(int idx),那么它应该能够捕获所有情况.

你必须ByteArray为每个迭代器返回分配一个新的,但希望这比复制你byte[]的每个迭代器返回要便宜得多.