Submit Search
ピュアJavaだと思った?残念androidでした~いつからAndroidをJavaだと錯覚していた?~
•
4 likes
•
7,106 views
JustSystems Corporation
Follow
DroidKaigi2018 Room 1 - 2018/02/08 14:00-14:30 の発表資料です。
Read less
Read more
1 of 92
Download now
Download to read offline
More Related Content
ピュアJavaだと思った?残念androidでした~いつからAndroidをJavaだと錯覚していた?~
1.
ピュアJavaだと思った? 残念Androidでした ~いつからAndroidをJavaだと錯覚していた?~ 空中清高
2.
空中清高 @soranakk ● 所属:ジャストシステム ○ スマイルゼミ中学生コース ■
ホームアプリ ■ システムアプリ ● Android開発歴:4年半ぐらい
3.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
4.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
5.
Oracle JavaとAndroid Javaの違い Android
JavaOracle Java ● javaはclassファイルにされ、さらにdexファ イルにコンパイルされる ● 実行環境はDalvik or ART ● javaはclassファイルにコンパイルされ る ● 実行環境はLinux, Mac OS, WindowsなどのJRE
6.
Oracle Javaの世界 JVM Java実行環境 rt.jar ● Object ●
String ● List … etc 標準ライブラリ classjava
7.
Android Javaの世界 Dalvik or
ART android.jar ● Object ● String ● List … etc 標準ライブラリ dexclass java
8.
Oracle JavaとAndroid Javaの違い Android
JavaOracle Java ● buildツール ● バイトコード ● 標準ライブラリ ● 実行マシン ● 実行OS ● etc...
9.
Oracle JavaとAndroid Javaの違い Android
JavaOracle Java ● buildツール ● バイトコード ● 標準ライブラリ ● 実行マシン ● 実行OS ● etc... 今日話すのはココ! 標準ライブラリの違い
10.
Oracle JavaとAndroid Javaの違い Android
JavaOracle Java rt.jar ● Object ● String ● List … etc 標準ライブラリ android.jar ● Object ● String ● List … etc 標準ライブラリ VS
11.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
12.
ArrayListの不思議な現象 List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { System.out.println("find!"); } System.out.println(str); }
13.
ArrayListの不思議な現象 > foo > bar >
find! > baz List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { System.out.println("find!"); } System.out.println(str); }
14.
for文中にあることをすると・・・おおっと List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); }
15.
for文中にあることをすると・・・おおっと > foo > bar >
baz > ConcurrentModificationException List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); }
16.
ConcurrentModificationException is 何? ●
マルチスレッドで同じArrayListを変更したときなどに発生する例外 ● シングルスレッドでもループ文などで発生することがある ● 仕組み(概要) ○ ArrayListは内部的に変更回数を持っている ○ Iteratorで変更回数をチェックしている ○ 変更回数がループ開始時点から変わっていたら例外を投げる 「あるはずの終端が無い!」とか、「終わったと思ったのにまだ残ってる!?」 とかを防ぐための機構。 JavaDocによると、「完全に防げるわけではない、best-effort」 https://docs.oracle.com/javase/9/docs/api/java/util/ConcurrentModificationExc eption.html
17.
ConcurrentModificationException is 何? ●
マルチスレッドで同じArrayListを変更したときなどに発生する例外 ● シングルスレッドでもループ文などで発生することがある ● 仕組み(概要) ○ ArrayListは内部的に変更回数を持っている ○ Iteratorで変更回数をチェックしている ○ 変更回数がループ開始時点から変わっていたら例外を投げる 「あるはずの終端が無い!」とか、「終わったと思ったのにまだ残ってる!?」 とかを防ぐための機構。 JavaDocによると、「完全に防げるわけではない、best-effort」 https://docs.oracle.com/javase/9/docs/api/java/util/ConcurrentModificationExc eption.html best-effort?
18.
List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } ArrayListの不思議な現象 > foo > bar > baz > ConcurrentModificationException
19.
List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } ArrayListの不思議な現象 List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } > foo > bar > baz > ConcurrentModificationException
20.
ArrayListの不思議な現象 List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } > foo > bar > baz > ConcurrentModificationException ココが違う
21.
ArrayListの不思議な現象 List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } > foo > bar > baz > ConcurrentModificationException ココが違う > foo > bar
22.
ArrayListの不思議な現象 List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } > foo > bar > baz > ConcurrentModificationException ココが違う 例外が発生しない!? > foo > bar
23.
ArrayListの不思議な現象 ● ConcurrentModificationExceptionの発生はbest-effort ● 例外は発生したり、しなかったりする ●
たとえばリストの最後から二番目をremoveしたときは発生しない
24.
ArrayListの不思議な現象 ● ConcurrentModificationExceptionの発生はbest-effort ● 例外は発生したり、しなかったりする ●
たとえばリストの最後から二番目をremoveしたときは発生しない Javaは不思議だなぁ Androidでも同じかなぁ?
25.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
26.
ピュアJavaだと思った?残念Androidでした List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } ココが違う
27.
ピュアJavaだと思った?残念Androidでした List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } ココが違う > foo > bar > baz > 例外発生 Oracle Java > foo > bar Oracle Java
28.
ピュアJavaだと思った?残念Androidでした > foo > bar >
baz List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } ココが違う > foo > bar > baz > 例外発生 Android JavaOracle Java > foo > bar > 例外発生 > foo > bar Android JavaOracle Java
29.
ピュアJavaだと思った?残念Androidでした > foo > bar >
baz List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } List<String> list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } ココが違う > foo > bar > baz > 例外発生 Android JavaOracle Java > foo > bar > 例外発生 > foo > bar Android JavaOracle Java JavaとAndroidで結果が違う
30.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
31.
ループ開始 ArrayListで例外が発生する仕組み:概要
32.
ループ開始 変更回数をチェック ArrayListで例外が発生する仕組み:概要
33.
ループ開始 変更回数をチェック あれ?変更回数が違ってる? ArrayListで例外が発生する仕組み:概要
34.
ループ開始 変更回数をチェック あれ?変更回数が違ってる? ArrayListで例外が発生する仕組み:概要 もしかするとあるはずの終端が無いかもしれない? 終わったと思ったのにまだ残ってるかもしれない!?
35.
ループ開始 変更回数をチェック List警察だ!例外を投げる! あれ?変更回数が違ってる? ArrayListで例外が発生する仕組み:概要 もしかするとあるはずの終端が無いかもしれない? 終わったと思ったのにまだ残ってるかもしれない!?
36.
ループ開始 変更回数をチェック List警察だ!例外を投げる! あれ?変更回数が違ってる? ArrayListで例外が発生する仕組み:概要 もしかするとあるはずの終端が無いかもしれない? 終わったと思ったのにまだ残ってるかもしれない!? 概要はわかったけど、 まだよくわかんないなぁ
37.
ループ開始 変更回数をチェック List警察だ!例外を投げる! あれ?変更回数が違ってる? ArrayListで例外が発生する仕組み:概要 もしかするとあるはずの終端が無いかもしれない? 終わったと思ったのにまだ残ってるかもしれない!? やっぱエンジニアだしコード で理解したい
38.
ArrayListで例外が発生する仕組み for (String str
: list) { ...省略 } 拡張for文は次のように展開されます https://jcp.org/aboutJava/communityprocess/jsr/tiger/enhanced-for.html for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); ...省略 }
39.
ArrayListで例外が発生する仕組み ● ListはmodCountというint値を持っている ● modCountはadd()
remove()などでインクリメントされる ● IteratorはmodCountを監視している Java 9.0.4 java.util.ArrayList.javaより一部抜粋 (872行あたりから) for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 } public Iterator<E> iterator() { return new Itr(); } class Itr implements Iterator<E> { int expectedModCount = modCount; …省略 }
40.
ArrayListで例外が発生する仕組み class Itr implements
Iterator<E> { int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } public E next() { checkForComodification(); int i = cursor; ...省略 cursor = i + 1; return (E) elementData[lastRet = i]; } …省略 Java 9.0.4 java.util.ArrayList.javaより一部抜粋 (872行あたりから) for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 }
41.
ArrayListで例外が発生する仕組み Java 9.0.4 java.util.ArrayList.javaより一部抜粋
(872行あたりから) final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 } class Itr implements Iterator<E> { int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } public E next() { checkForComodification(); int i = cursor; ...省略 cursor = i + 1; return (E) elementData[lastRet = i]; } …省略
42.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); }
43.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
44.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
45.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3
46.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2
47.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == true で継続
48.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == true で継続 next()のcheckForComodification()で modCount != expectedModCount == true
49.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == true で継続 next()のcheckForComodification()で modCount != expectedModCount == true ん~・・・
50.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == true で継続 next()のcheckForComodification()で modCount != expectedModCount == true 変わってる
51.
例外発生の仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == true で継続 next()のcheckForComodification()で modCount != expectedModCount == true List警察だ!例外を投げる! 変わってる
52.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); }
53.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
54.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
55.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2
56.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2
57.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == false でループ終了
58.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == false でループ終了 next()は呼ばれないので checkForComodification()は呼ばれない
59.
例外が発生しない仕組み Oracle Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } ・・・ 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2 次のhasNext()はcursor != size == false でループ終了 next()は呼ばれないので checkForComodification()は呼ばれない
60.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
61.
いつからAndroidをJavaだと錯覚していた? Java 9.0.4 java.util.ArrayList.javaより一部抜粋
(872行あたりから) final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 } class Itr implements Iterator<E> { int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } public E next() { checkForComodification(); int i = cursor; ...省略 cursor = i + 1; return (E) elementData[lastRet = i]; } …省略
62.
いつからAndroidをJavaだと錯覚していた? for (Iterator<String> iter
= list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 } class Itr implements Iterator<E> { protected int limit = ArrayList.this.size; int expectedModCount = modCount; public boolean hasNext() { return cursor < limit; } public E next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); int i = cursor; ...省略 cursor = i + 1; return (E) elementData[lastRet = i]; } ...省略 Android 26 java.util.ArrayList.javaより一部抜粋 (833行あたりから)
63.
class Itr implements
Iterator<E> { protected int limit = ArrayList.this.size; int expectedModCount = modCount; public boolean hasNext() { return cursor < limit; } public E next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); int i = cursor; ...省略 cursor = i + 1; return (E) elementData[lastRet = i]; } ...省略 いつからAndroidをJavaだと錯覚していた? limitが追加され、 hasNext()の条件が変わっている listのsizeが変わっても、limitは固 定されているので hasNext()の動作が変わった! for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); …省略 } Android 26 java.util.ArrayList.javaより一部抜粋 (833行あたりから)
64.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); }
65.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
66.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
67.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3
68.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2だけどlimit = 3のまま
69.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == false でループ終了
70.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == false でループ終了 next()は呼ばれないので modCount != expectedModCount はチェックされない
71.
例外が発生しない仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "baz"のときcursor = 3 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == false でループ終了 next()は呼ばれないので modCount != expectedModCount はチェックされない ・・・
72.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); }
73.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (String str : list) { if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
74.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される
75.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2
76.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま
77.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == true で継続
78.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == true で継続 next()で modCount != expectedModCount == true
79.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } ん~・・・ 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == true で継続 next()で modCount != expectedModCount == true
80.
例外発生の仕組み Android Java List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == true で継続 next()で modCount != expectedModCount == true 変わってる
81.
例外発生の仕組み Android Java List警察だ!例外を投げる! List<String>
list = new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("bar".equals(str)) { list.remove(str); } System.out.println(str); } 拡張for文が展開される str == "bar"のときcursor = 2 remove(str)でmodCount++, size = 2だけどlimit = 3のまま 次のhasNext()はcursor < limit == true で継続 next()で modCount != expectedModCount == true 変わってる
82.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
83.
AndroidとJavaはAPIが同じなだけ Oracle Java ● ConcurrentModificationExceptionの発生はbest-effort ●
例外は発生したり、しなかったりする ● たとえばリストの最後から二番目をremoveしたときは発生しない Android Java ● ConcurrentModificationExceptionの発生はbest-effort ● 例外は発生したり、しなかったりする ● たとえばリストの最後をremoveしたときは発生しない
84.
AndroidとJavaはAPIが同じなだけ Oracle Java ● ConcurrentModificationExceptionの発生はbest-effort ●
例外は発生したり、しなかったりする ● たとえばリストの最後から二番目をremoveしたときは発生しない Android Java ● ConcurrentModificationExceptionの発生はbest-effort ● 例外は発生したり、しなかったりする ● たとえばリストの最後をremoveしたときは発生しない 標準ライブラリが違う!
85.
目次 Oracle JavaとAndroid Javaの違い ArrayListの不思議な現象 ピュアJavaだと思った?残念Androidでした ArrayListで例外が発生する仕組み いつからAndroidをJavaだと錯覚していた? AndroidとJavaはAPIが同じなだけ その他の事例もあるぞ(先駆者紹介)
86.
その他の事例もあるぞ(先駆者紹介) ● Java と
Android の正規表現の動作の違い https://qiita.com/KeithYokoma/items/2915a904a18760ee67c4 ○ 正規表現ライブラリの違いに解説されています ● Android Javaの正規表現の落とし穴 https://www.ecoop.net/memo/archives/regular-expression-problem-o-android-java.html ○ こちらも正規表現ですが、Stringクラスの違いについて解説されています
87.
ご静聴ありがとうございました。
88.
細かい補足 じゃあfor文中にリストから削除したいときはどうしたらいいの? 拡張for文の中でlist#removeは使ってはいけません。 代わりにIteratorでfor文を回して、Iterator#removeを使いましょう。 あるいはKotlinのfilterを使うと良いです。 List<String> list =
new ArrayList<>(); list.add("foo"); list.add("bar"); list.add("baz"); for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { String str = iter.next(); if ("baz".equals(str)) { iter.remove(); } System.out.println(str); }
89.
細かい補足 Android N 以降はOpen
JDKを使っているって聞いたけど? はい、その通りです。 でも実はAndroidのJavaはOpen JDKからさらに変更を加えています そのため、今回紹介したArrayListの操作では Open JDK != Android Java となります。 Open JDKだと思った? 残念Androidでした コミットログ https://android.googlesource.com/platform/libcore/+/b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194
90.
細かい補足 Android N より前はHarmonyを使っているって聞いたけど? はい、その通りです。 でも実はAndroidのJavaはApache
Harmonyからさらに変更を加えています そのため、今回紹介したArrayListの操作では Apache Harmony != Android Java となります。 Apache Harmonyだと思った? 残念Androidでした コミットログ https://android.googlesource.com/platform/libcore/+/7de2d41b95fc968b0ccc530c28d66f003ff9ab2a
91.
細かい補足 なんでこんな違いが生まれたの? コミットコメントやソースコードのコメントを読んでみると Android側は意図して修正しています。 Open JDKのhasNext()はlistのsizeに依存して false返したりtrue返したりするので、固定させるために修正したみたいです。 コミットログ https://android.googlesource.com/platform/libcore/+/b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194 ソースコードのコメント https://android.googlesource.com/platform/libcore/+/master/ojluni/src/main/java/java/util/ArrayList.jav a#841
92.
ご静聴ありがとうございました。
Download