Javaを始めたときにコケたので思い出深いのですが、C++ とJavaってイテレータの概念が全然違いますね。
C++ のイテレータはコレクションの要素そのものを指しています。N個要素を持つ配列aのイテレータitであれば、a.begin() はa[0] を指し、itはa[0] からa[N - 1] の間まで有効な要素を指し続けます。a.end() は存在しないa[N] を指します。
begin() end()
| |
a[0] a[1] a[2] ... a[N - 2] a[N - 1] a[N]
| コレクションの有効範囲 |
C++ 方式の利点は、イテレータが何を指すのか直感的に理解しやすく、イテレータ経由での要素の書き換えや削除のイメージが沸きやすいことです。
欠点はbegin() は参照して良いのに、end() は参照してはいけない、という非対称な仕様になってしまうことです。例えば、逆転イテレータ(reverse_iterator)を実装するとbegin() をend(), ++ を -- として扱うだけでは作れずに、悲しい思いをします。
Javaのイテレータは要素と要素の「間」を指しています。Javaにbegin(), end() はありませんが、対比のため無理やり書くと下記のようなイメージです。
begin() = iterator() end() = hasNext() がfalse
| |
a[0] a[1] a[2] ... a[N - 2] a[N - 1]
| コレクションの有効範囲 |
Java方式の利点はbeginとendが対称的になることです。もうbeginとendで悲しい思いをすることはありません。
欠点は書き換えや削除の対象がわかりづらいことです。特に双方向イテレータ(ListIterator)が顕著なので、もう少し詳しくご紹介しましょうか。
Javaコレクションの仕様ではイテレータが「最後に返した要素」が書き換え(set)や削除(remove)の対象、となります。ListIteratorは進む/戻るのどちらもできますから、イテレータの現在位置の「直前」あるいは「直後」どちらかの要素が対象となります。下記に図示します。
最後の操作がnext() だった場合
------------------------------
set()/remove() の対象
| 現在位置
| |
a[0] a[1] a[2] ...
最後の操作がprevious() だった場合
----------------------------------
現在位置
| set()/remove() の対象
| |
a[0] a[1] a[2] ...
現在位置が全く同じでもset()/remove() の対象が変わる、この動きは正直ややこしいです。
利点の両立は難しいでしょうから、あとは皆さんの好みでしょうか。私は対称性を取ってJava方式に一票かなあ…。
< | 2014 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)