LoginSignup
1
0

More than 5 years have passed since last update.

Java7環境ではhashのforEachに気をつける

Posted at

Kotlinで書いたプログラムをJava7な環境で動かしたら罠にかかったので自分用にメモします。

起きたこと

以下のようにHashmapにforEachで処理を書くと、Java8以降では問題ないのにJava7の環境下ではエラーが発生して実行できません。


    val hash = hashMapOf("hoge" to "fuga", "foo" to "bar")

    hash.forEach { key, value ->
        System.out.println("$key is $value")
    }
Exception in thread "main" java.lang.NoClassDefFoundError: java/util/function/BiConsumer

解決方法

forEach{ key, value ->}forEach{ (key, value) ->}とするか、もしくはforEach{ entry -> entry.key}とする。

動くコード


    val hash = hashMapOf("hoge" to "fuga", "foo" to "bar")

    hash.forEach { (key, value) ->
        System.out.println("$key is $value")
    }

どうしてこうなるのか

()のあるなしでそんな違いがあるのかと思いますが、大ありでした。

最初のようにforEach{key, value ->}と書いた場合、java.util.HashMapのforEachメソッドが直接呼びされます。
このメソッドの定義は以下の通り。

    public void forEach(BiConsumer<? super K, ? super V> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e.key, e.value);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

ご覧の通り、keyとvalueのセットをBiConsumerで受け取っているのがわかります。
このBiConsumerはJava8で導入されたものなので、Java7環境では当然動かなかったということでした。

一方で動くケース(forEach{(key, value) ->}forEach{ entry -> })ではkotlin.collectionで定義されているforEachメソッドが呼ばれるので、7以前のJavaでも問題なく実行できます。

そろそろJava7の環境もなくなってくると思いますが、もし7で動かす可能性のあるプログラムなら気をつけておきたいところです。

参考

https://stackoverflow.com/a/46397602

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0