Java : 回答編(3)

[id:lethevert:20070415:p1]
こっちも回答してしまいましょう。

void f (HashMap<K,V> m) {
  for (K k: m.keySet()) {
    g (k, m.get(k))
  }
}

以下ネタバレ注意
観点は3つです。一つ目は、Map#entrySet()を使うということ。こうしないと、m.get(k)のところで余分な探索を行うことになって効率が悪くなります。

  for (Map.Entry<K,V> e: m.entrySet()) {
    g (e.getKey(), e.getValue());
  }

もうひとつは、前回と同じ、関数の引数はなるべく上位のインターフェースで受けるということ。ここでは、TreeMapなども受け取れるようにMapインターフェースを使います。

void f (Map<K,V> m)

最後のひとつは、JavaGenericsはcovariantではないので、その辺をきちんと指定してあげないといけない。

void f (Map<? extends K, ? extends V> m) {
  for (Map.Entry<? extends K, ? extends V> e: m.entrySet()) {
    g (e.getKey(), e.getValue());
  }
}

ただ、こうなってくると、JavaGenerics型推論がないことによるめんどくささが際立ってきているような気がします。
なお、前回の最後のJava 5の例も、前回のテーマではなかったので突っ込まなかったですが、次のように書くべき所です。

void f (Iterable<? extends E> c) {
  for (E e: c) {
    g(e);
  }
}