Top Banner
Java Puzzlers 櫻櫻 櫻櫻櫻 櫻櫻 Dedicated to John Carpenter
48

Java Puzzlers JJUG CCC 2016

Apr 16, 2017

Download

Technology

Yoshio Terada
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Java Puzzlers JJUG CCC 2016

Java Puzzlers

櫻庭 祐一

寺田 佳央

Dedicated to John Carpenter

Page 2: Java Puzzlers JJUG CCC 2016

We are Click and Hack the Type-It brothers !!

Page 3: Java Puzzlers JJUG CCC 2016

コード中に発生する勘違い Java プログラミングにおける  奇妙な振る舞いをする小さなプログラム  複数の選択肢から、何が表示される?  ミステリーの解明  問題の解決方法  教訓

Page 4: Java Puzzlers JJUG CCC 2016

Java Puzzlers のルール public class JavaPuzzlers { public static void main(String... args) { System.out.println(“Japan Java User Group Presents!”); } }

1.Japan Java User Group Presents!2.Java Puzzlers3.0xCAFEBABE4.その他

Page 5: Java Puzzlers JJUG CCC 2016

1問目

Page 6: Java Puzzlers JJUG CCC 2016

問題1: They Livepublic class TheyLive { public static void main(String... args) { int sum = 0; for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { if (i != 0) sum += i / Math.abs(i); } System.out.println(sum); }}

Page 7: Java Puzzlers JJUG CCC 2016

選択肢1: They Live

選択肢1. -12. 03. 14.その他

public class TheyLive { public static void main(String... args) { int sum = 0; for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { if (i != 0) sum += i / Math.abs(i); } System.out.println(sum); }}

Page 8: Java Puzzlers JJUG CCC 2016

正解は ?!

Page 9: Java Puzzlers JJUG CCC 2016

解答1: They Live

選択肢1. -12. 03. 14.その他

public class TheyLive { public static void main(String... args) { int sum = 0; for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { if (i != 0) sum += i / Math.abs(i); } System.out.println(sum); }}

Page 10: Java Puzzlers JJUG CCC 2016

解説1:何が悪いのか?

-2147483648/abs(-2147483648) = -1-2147483647/abs(-2147483648) = -1

2147483646/abs(2147483646) = +1+)

……

-2

Page 11: Java Puzzlers JJUG CCC 2016

解説1:何が悪いのか?

-2147483648/abs(-2147483648) = +1-2147483647/abs(-2147483648) = -1

2147483646/abs(2147483646) = +1+)

……

0

Page 12: Java Puzzlers JJUG CCC 2016

解決1:どうやって直すのかpublic class TheyLive { public static void main(String... args) { int sum = -1;      for (int i = Integer.MIN_VALUE+1; i < Integer.MAX_VALUE; i++) { if (i != 0) sum += i / Math.abs(i); } System.out.println(sum); }}

Page 13: Java Puzzlers JJUG CCC 2016

教訓1:

• 意図しない動作をするメソッドが存在する

• 使用時には必ず Javadoc をチェックしよう

• メソッドを作成する場合には、

想像しやすい動作になるよう心がけよう

Page 14: Java Puzzlers JJUG CCC 2016

2問目

Page 15: Java Puzzlers JJUG CCC 2016

問題2: MarshmallowManpublic class MarshmallowMan{ public static void main(String... args) { int sum = 0; for (int i = 1; i <= 10; i++) { sum += foo(i); } System.out.println(sum); } public static long foo(long l) {return l;}}

Page 16: Java Puzzlers JJUG CCC 2016

選択肢2: MarshmallowManpublic class MarshmallowMan { public static void main(String... args) { int sum = 0; for (int i = 1; i <= 10; i++) { sum += foo(i); } System.out.println(sum); } public static long foo(long l) {return l;}}

選択肢1. 02. 453. 554. コンパイルエ

ラー

Page 17: Java Puzzlers JJUG CCC 2016

正解は ?!

Page 18: Java Puzzlers JJUG CCC 2016

選択肢2: MarshmallowManpublic class Sum { public static void main(String... args) { int sum = 0; for (int i = 1; i <= 10; i++) { sum += foo(i); } System.out.println(sum); } public static long foo(long l) {return l;}}

選択肢1. 02. 453. 554. コンパイルエ

ラー

Page 19: Java Puzzlers JJUG CCC 2016

解説2:

sum = sum + data コンパイルエラー sum += data コンパイルエラーにはならない

int sum = 0;long data = 10;System.out.println(sum += data);

この問題と同じ

Page 20: Java Puzzlers JJUG CCC 2016

解説2:JLS §15.26.2. Compound Assignment Operators

E1 op= E2E1 = (T) ((E1) op (E2)) ※ T は E1 の型

つまりsum = (int) (sum + data)

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2

Page 21: Java Puzzlers JJUG CCC 2016

解決2: Java 8 以降での計算処理

IntStream.rangeClosed(1, 10).sum()

桁があふれた際に ArithmeticException を出力

java.lang.StrictMath#addExactjava.lang.Math#addExact

java.util.concurrent.atomic.LongAdderjava.util.concurrent.atomic.DoubleAdder複数スレッドからの更新で Atomic 性を保つ場合AtomicLong よりおすすめ

Page 22: Java Puzzlers JJUG CCC 2016

教訓2:

• 演算子の振る舞いについて正しく理解しましょ

• 何が最適な解決方法か考えましょう

Page 23: Java Puzzlers JJUG CCC 2016

3問目

Page 24: Java Puzzlers JJUG CCC 2016

問題3: The Thingpublic class TheThing { public static void main(String... args) { StringBuilder builder = new StringBuilder("J"); builder = builder.append("a"); Stream.of("v", "a") .forEach(builder::append); System.out.println(builder); }}

Page 25: Java Puzzlers JJUG CCC 2016

選択肢3: The Thingpublic class TheThing { public static void main(String... args) { StringBuilder builder = new StringBuilder("J"); builder = builder.append("a"); Stream.of("v", "a") .forEach(builder::append); System.out.println(builder); }}

選択肢1.Ja2.Java3.Compile Error4.Exception

Page 26: Java Puzzlers JJUG CCC 2016

正解は ?!

Page 27: Java Puzzlers JJUG CCC 2016

選択肢3: The Thingpublic class TheThing { public static void main(String... args) { StringBuilder builder = new StringBuilder("J"); builder = builder.append("a"); Stream.of("v", "a") .forEach(builder::append); System.out.println(builder); }}

選択肢1.Ja2.Java3.Compile Error4.Exception

Page 28: Java Puzzlers JJUG CCC 2016

解説3:何が悪いのか?ラムダ式 :final 以外のローカル変数にアクセスできない

StringBuilder builder = new StringBuilder("J");builder = builder.append("a");

// NG Stream.of("v", "a") .forEach(c -> builder.append(c));

Page 29: Java Puzzlers JJUG CCC 2016

解説3:何が悪いのか?ラムダ式 :final 以外のローカル変数にアクセスできない

// Effectively FinalStringBuilder builder = new StringBuilder("Ja");

// OK Stream.of("v", "a") .forEach(c -> builder.append(c));

Page 30: Java Puzzlers JJUG CCC 2016

解説3:何が悪いのか?メソッド参照 :final でないローカル変数にアクセスできるい

StringBuilder builder = new StringBuilder("J");builder = builder.append("a"); // Not-Final

// OKStream.of("v", "a") .forEach(builder::append);

Page 31: Java Puzzlers JJUG CCC 2016

教訓3:

• ラムダ式とメソッド参照はほぼ同じだが、若干の違

いがあることを意識しよう

• ラムダ式と匿名クラスも違いがあるので、気をつけ

よう

• this の扱いが異なる

• メソッド参照の使いすぎに注意しよう

• 他の人が読めないコードになりがち

Page 32: Java Puzzlers JJUG CCC 2016

4問目

Page 33: Java Puzzlers JJUG CCC 2016

問題4: OpenSesame public class OpenSesame {    public static void main(String... argv){        List<Integer> integerList = Arrays.asList(1,2,3,4,5);        List<Integer> filterdData = integerList.stream()                             .filter((int i) -> (i > 2))               .collect(Collectors.toList());        System.out.println(filterdData);    } }

Page 34: Java Puzzlers JJUG CCC 2016

選択肢4: OpenSesame public class OpenSesame {    public static void main(String... argv){        List<Integer> integerList = Arrays.asList(1,2,3,4,5);        List<Integer> filterdData = integerList.stream()                           .filter((int i) -> (i > 2))               .collect(Collectors.toList());        System.out.println(filterdData);    } }

選択肢1. 1,22. 3,4,53. 何も表示されない4. コンパイルエラー

Page 35: Java Puzzlers JJUG CCC 2016

正解は ?!

Page 36: Java Puzzlers JJUG CCC 2016

解答4: OpenSesame public class OpenSesame {    public static void main(String... argv){        List<Integer> integerList = Arrays.asList(1,2,3,4,5);        List<Integer> filterdData = integerList.stream()                              .filter((int i) -> (i > 2))               .collect(Collectors.toList());        System.out.println(filterdData);    } }

選択肢1. 1,22. 3,4,53. 何も表示されない4. コンパイルエラー

Page 37: Java Puzzlers JJUG CCC 2016

解説4:何が悪いのか? public class OpenSesame {    public static void main(String... argv){        List<Integer> integerList = Arrays.asList(1,2,3,4,5);        List<Integer> filterdData = integerList.stream()                .filter((int i) -> (i > 2))                .collect(Collectors.toList());        System.out.println(filterdData);    } }

期待する型が見つからない

クラス Test のメソッド filter は指定された型に適用できません 期待値: List<T>, Predicate<T> 検出値: List, (int i) -> (i>2)

Page 38: Java Puzzlers JJUG CCC 2016

解決4: IntStream を使いましょう public class OpenSesame {    public static void main(String... argv){ int[] filterdData = IntStream.range(1, 6) .filter(i -> i > 2) .toArray(); System.out.println(Arrays.toString(filterdData));    } }

Page 39: Java Puzzlers JJUG CCC 2016

教訓4:

• Lambda 式を記述する場合、部分的に型を

 書くくらいならば 型を省略しましょう

• primitive 型を使用する場合、対応する

Stream を使いましょう

Page 40: Java Puzzlers JJUG CCC 2016

5問目

Page 41: Java Puzzlers JJUG CCC 2016

問題5: The Fogclass Ship<T> { private T t; public Ship(T t) { this.t = t; } public void setCrew(T t) { this.t = t; } public int hashCode() { return Objects.hashCode(t); }}public class TheFog { public static void main(String... args) { Map<Ship<String>, String> map = new HashMap<>(); Ship<String> a = new Ship<>("A"); Ship<String> b = new Ship<>("B"); map.put(a, "a"); a.setCrew("B"); map.put(b, "b"); System.out.println(map.values().size()); }}

Page 42: Java Puzzlers JJUG CCC 2016

選択肢5: The Fogclass Ship<T> { private T t; public Ship(T t) { this.t = t; } public void setCrew(T t) { this.t = t; } public int hashCode() { return Objects.hashCode(t); }}public class TheFog { public static void main(String... args) { Map<Ship<String>, String> map = new HashMap<>(); Ship<String> a = new Ship<>("A"); Ship<String> b = new Ship<>("B"); map.put(a, "a"); a.setCrew("B"); map.put(b, "b"); System.out.println(map.values().size()); }}

選択肢1. 02. 13. 24. Exception

Page 43: Java Puzzlers JJUG CCC 2016

正解は ?!

Page 44: Java Puzzlers JJUG CCC 2016

解答5: The Fogclass Ship<T> { private T t; public Ship(T t) { this.t = t; } public void setCrew(T t) { this.t = t; } public int hashCode() { return Objects.hashCode(t); }}public class TheFog { public static void main(String... args) { Map<Ship<String>, String> map = new HashMap<>(); Ship<String> a = new Ship<>("A"); Ship<String> b = new Ship<>("B"); map.put(a, "a"); a.setCrew("B"); map.put(b, "b"); System.out.println(map.values().size()); }}

選択肢1. 02. 13. 24. Exception

Page 45: Java Puzzlers JJUG CCC 2016

解説5:

• Map は Key のハッシュ値を使用する

• 同じハッシュ値を put すると、上書きする

• ハッシュ値が後から変更された場合、同じハッシュ値の

エントリがあっても存在し続ける

• しかし、そのエントリにはアクセスできない

• Mutable なオブジェクトを Map のキーにすることは

危険

Page 46: Java Puzzlers JJUG CCC 2016

解決5class Ship<T> { private T t; public Ship(T t) { this.t = t; }// public void setCrew(T t) { this.t = t; } public int hashCode() { return Objects.hashCode(t); }}public class TheFog { public static void main(String... args) { Map<Ship<String>, String> map = new HashMap<>(); Ship<String> a = new Ship<>("A"); Ship<String> b = new Ship<>("B"); map.put(a, "a"); // a.setCrew("B"); map.put(b, "b"); System.out.println(map.values().size()); }}

Page 47: Java Puzzlers JJUG CCC 2016

教訓5:

• Mutable なオブジェクトを Map のキーにしない

• Imutable なオブジェクトを使い慣れよう

• hashCode メソッドをオーバーライドする場合、必

ず equals メソッドもオーバーライドする

Page 48: Java Puzzlers JJUG CCC 2016

Java Puzzlers

櫻庭 祐一

寺田 佳央

Dedicated to John Carpenter