from old Java to modern Java

29,087 views

Published on

JJUGナイトセミナー2013年6月の発表資料です

Published in: Technology, News & Politics
3 Comments
126 Likes
Statistics
Notes
No Downloads
Views
Total views
29,087
On SlideShare
0
From Embeds
0
Number of Embeds
4,564
Actions
Shares
0
Downloads
152
Comments
3
Likes
126
Embeds 0
No embeds

No notes for slide

from old Java to modern Java

  1. 1. from old Javato modern Java∼ 職業プログラマに聞いて欲しいJava再入門Acroquest Technology株式会社JJUG / 関西Javaエンジニアの会谷本 心 ( @cero_t )
  2. 2. 自己紹介•職業:Javaトラブルシューター(教育もやってます)•近況:gihyo.jpや日経ソフトウエアに記事を書きました
  3. 3. ENdoSnipeというOSSのJava解析・可視化ツールをgihyo.jpで紹介しました記事の検索:endosnipe gihyo公式サイト:http://www.endosnipe.com
  4. 4. 日経ソフトウエア2013年7月号の特集記事「そのコードは古い」のJava編を執筆しました同僚と一緒に「Javaのイケてるコード、残念なコード」を連載していました(4月号まで)購入:http://www.amazon.co.jp
  5. 5. 本日のテーマイマドキのJava(文法編)
  6. 6. Javaの文法の話新しいAPIの話解析ツールの話バイトコードの話
  7. 7. いま、現場ではどのバージョンのJavaをお使いですか?(複数回答可)
  8. 8. もちろんJavaSE7
  9. 9. 既にOracleのサポートが切れたJavaSE6
  10. 10. え、まだJ2SE 5.0ですか?
  11. 11. まさかのJ2SE 1.4ですか?
  12. 12. それより前?
  13. 13. 大丈夫です、今回は1.4や5.0あたりを使っている人が一番のターゲットです
  14. 14. 逆にJavaSE8?
  15. 15. すごいね、帰っていいよ!
  16. 16. from old Javato modern Java∼ 職業プログラマに聞いて欲しいJava再入門Acroquest Technology株式会社JJUG / 関西Javaエンジニアの会谷本 心 ( @cero_t )
  17. 17. Lesson1
  18. 18. 現場で見かけるこんなコード
  19. 19. private List m_list = null;private int process_file(String str_file_name) {String str_line;List list_lines = new ArrayList();int i_result = read_file(str_file_name, list_lines);if (i_result == 0) {List list_record = new ArrayList();for (int i = 0; i < list_lines.size(); i++) {str_line = (String) list_lines.get(i);Record record = new Record();i_result = parse_line(str_line, record);if (i_result != 0) {return i_result;}list_recordord.add(record);}m_list = list_record;return 0;} else {return i_result;}}
  20. 20. Lesson1from C-ish Javato Java like Java(J2SE1.4)
  21. 21. private List m_list = null;private int process_file(String str_file_name) {String str_line;List list_lines = new ArrayList();int i_result = read_file(str_file_name, list_lines);if (i_result == 0) {List list_record = new ArrayList();...
  22. 22. private List m_list = null;private int process_file(String str_file_name) {String str_line;List list_lines = new ArrayList();int i_result = read_file(str_file_name, list_lines);if (i_result == 0) {List list_record = new ArrayList();...メンバ変数だと分かるよう、先頭にm_ を付けようスネークケースの方が読みやすいよね変数は先頭でまとめて宣言もちろんハンガリアン記法さ!戻り値を複数返したい時は、引数に戻り値相当の変数参照を渡せばいいんだよ関数の戻り値はもちろん0が正常、それ以外が異常
  23. 23. for (int i = 0; i < list_lines.size(); i++) {str_line = (String) list_lines.get(i);Record record = new Record();i_result = parse_line(str_line, record);if (i_result != 0) {return i_result;}list_recordord.add(record);}m_list = list_record;return 0;
  24. 24. for (int i = 0; i < list_lines.size(); i++) {str_line = (String) list_lines.get(i);Record record = new Record();i_result = parse_line(str_line, record);if (i_result != 0) {return i_result;}list_recordord.add(record);}m_list = list_record;return 0;下の関数でエラーが出たらちゃんとエラーコードを上に伝播させないとね正常終了はいつもreturn 0;
  25. 25. きちんとJava風に書き直すと・・・
  26. 26. private List resultList;private List processFile(String fileName)throws SystemException {List lines = readFile(fileName);List recordList = new ArrayList();for (int i = 0; i < lines.size(); i++) {String line = (String) lines.get(i);Record record = parseLine(line);recordList.add(record);}return recordList;}
  27. 27. private List resultList;private List processFile(String fileName)throws SystemException {List lines = readFile(fileName);List recordList = new ArrayList();for (int i = 0; i < lines.size(); i++) {String line = (String) lines.get(i);Record record = parseLine(line);recordList.add(record);}return recordList;}メンバ変数に接頭辞やthisはつけないキャメルケースエラーはExceptionで表現して伝播させるエラーコードではなく普通に値を返す変数は使う直前に宣言引数に戻り値への参照を渡さないNo ハンガリアン
  28. 28. before / afterで見てみると
  29. 29. before
  30. 30. private List m_list = null;private int process_file(String str_file_name) {String str_line;List list_lines = new ArrayList();int i_result = read_file(str_file_name, list_lines);if (i_result == 0) {List list_record = new ArrayList();for (int i = 0; i < list_lines.size(); i++) {str_line = (String) list_lines.get(i);Record record = new Record();i_result = parse_line(str_line, record);if (i_result != 0) {return i_result;}list_recordord.add(record);}m_list = list_record;return 0;} else {return i_result;}}
  31. 31. after
  32. 32. private List resultList;private List processFile(String fileName)throws SystemException {List lines = readFile(fileName);List recordList = new ArrayList();for (int i = 0; i < lines.size(); i++) {String line = (String) lines.get(i);Record record = parseLine(line);recordList.add(record);}return recordList;}
  33. 33. なんということでしょう
  34. 34. No C-ish Java like1メンバ変数は見やすいように接頭辞をつけるメンバ変数はIDEが色をつけるから接頭辞もthisも不要2 スネークケース 文化的にキャメルケース3変数は先頭で宣言しないと怒られるしメモリ解放し忘れる変数は使っている場所が分かるよう使う直前に宣言する4関数の戻り値でエラーを表現0を返せば正常エラーはExceptionで表現値が普通に返れば正常5 引数に戻り値の参照を渡すと良いメソッドの引数はできるだけ変更しない(特に戻り値がある場合)Lesson1 まとめ
  35. 35. Lesson2from J2SE 1.4to J2SE 5.0
  36. 36. ちなみに正式名称はJavaSE 5.0ではなくJ2SE 5.0らしいよ
  37. 37. J2SE 5.0
  38. 38. Generics foreachenumstatic importvar argsauto boxing... and more
  39. 39. イマドキのJavaのスタンダード
  40. 40. before
  41. 41. private List processFile(String fileName)throws SystemException {List lines = readFile(fileName);List recordList = new ArrayList();for (int i = 0; i < lines.size(); i++) {String line = (String) lines.get(i);Record record = parseLine(line);recordList.add(record);}return recordList;}
  42. 42. after
  43. 43. private List<Record> processFile(String fileName)throws SystemException {List<String> lines = readFile(fileName);List<Record> recordList = new ArrayList<Record>();for (String line : lines) {Record record = parseLine(line);recordList.add(record);}return recordList;}
  44. 44. private List<Record> processFile(String fileName)throws SystemException {List<String> lines = readFile(fileName);List<Record> recordList = new ArrayList<Record>();for (String line : lines) {Record record = parseLine(line);recordList.add(record);}return recordList;}全体的にGenericsを使って型を明確にするforeach文(拡張for文)でシンプルにループ処理を行なう
  45. 45. 簡単すぎたのでもう一つ。
  46. 46. public interface Constants {public static final int FILE_NOT_FOUND = -1;public static final int FILE_READ_ERROR = -2;public static final int FILE_EMPTY = -3;public static final int RECORD_EMPTY = -4;public static final int RECORD_SIZE_ERROR = -5;public static final int RECORD_BODY_EMPTY = -6;}
  47. 47. public class FileProcessor implements Constants {private List readFile(String fileName) {List lines = new ArrayList();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}}
  48. 48. public class FileProcessor implements Constants {private List readFile(String fileName) {List lines = new ArrayList();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}}定数インタフェースという優れたテクニック定数クラス名を省略して記載できるんですよ!
  49. 49. あると思います
  50. 50. public enum ErrorCode {FILE_NOT_FOUND, FILE_READ_ERROR, FILE_EMPTY, RECORD_EMPTY, RECORD_SIZE_ERROR, RECORD_BODY_EMPTY, RECODE_CODE_NOT_NUMERIC;}列挙するならenum
  51. 51. import static ErrorCode.*;public class FileProcessor {private List<String> readFile(String fileName) {List<String> lines = new ArrayList<String>();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}}定数クラス名を省略して記載できるんですよ!static importで定数クラス(enum)全体をimport
  52. 52. import staticが1つ以上あったら * になるようIDEを設定しておくと良い
  53. 53. No J2SE 1.4 J2SE 5.01 Objectだけを扱うCollection Genericsを使ったCollection2for (int i=0; i < list.size(); i++)while (iterator.hasNext())for (String value : list)3 定数インタフェースは便利 static importで定数を宣言する4 int値を使ってコード一覧を作成 enumを使って列挙するLesson2 まとめ
  54. 54. Lesson3from J2SE 5.0to JavaSE 6
  55. 55. JavaSE 6では、文法面はほとんど変化なし(ツール、APIの強化のみ)
  56. 56. ちなみに、API変更のおかげでnative2asciiを使わなくて済むようになったけど
  57. 57. native2asciiを使う方が安全だから結局みんな使ってる(実際はIDEで変換)
  58. 58. No J2SE 5.0 JavaSE 61native2asciiは面倒だからIDEのプロパティファイル編集機能を使うnative2asciiは面倒だからIDEのプロパティファイル編集機能を使うLesson3 まとめ
  59. 59. Lesson4from JavaSE 6to JavaSE 7
  60. 60. JavaSE 7
  61. 61. try-with-resourcesdiamond operatornio2multi-catch... and more
  62. 62. この辺からちょっと理解が怪しくなる人が多い
  63. 63. private List<String> readFile(String fileName) {List<String> lines = new ArrayList<String>();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}
  64. 64. private List<String> readFile(String fileName) {List<String> lines = new ArrayList<String>();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}finallyでcloseしないとリソースのクローズ漏れを起こして大変ですよね別に起きないしいいよね
  65. 65. 敢えて言えば
  66. 66. finallyでcloseするのは古い定石
  67. 67. private List<String> readFile(String fileName) {List<String> lines = new ArrayList<>();try (FileReader in = new FileReader(fileName);BufferedReader reader= new BufferedReader(in)) {String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);}return lines;}
  68. 68. private List<String> readFile(String fileName) {List<String> lines = new ArrayList<>();try (FileReader in = new FileReader(fileName);BufferedReader reader= new BufferedReader(in)) {String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);}return lines;}tryでリソースを宣言するとtryブロックから抜ける時にクローズされる密かにdiamond
  69. 69. まぁファイル読むだけなら
  70. 70. private List<String> readFile(String fileName) {try {return Files.readAllLines(Paths.get(fileName),Charset.defaultCharset());} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);}}
  71. 71. private List<String> readFile(String fileName) {try {return Files.readAllLines(Paths.get(fileName),Charset.defaultCharset());} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);}}NIO2で追加された新しいファイルAPIのひとつ
  72. 72. これでもうGroovyの人とかにプギャーされなくなる
  73. 73. before
  74. 74. private List<String> readFile(String fileName) {List<String> lines = new ArrayList<String>();BufferedReader reader = null;try {reader = new BufferedReader(new FileReader(fileName));String line;while ((line = reader.readLine()) != null) {lines.add(line);}} catch (FileNotFoundException ex) {throw new SystemException(FILE_NOT_FOUND, ex);} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);} finally {try {if (reader != null) {reader.close();}} catch (IOException ex) {// この例外は無視する?}}return lines;}
  75. 75. after
  76. 76. private List<String> readFile(String fileName) {try {return Files.readAllLines(Paths.get(fileName),Charset.defaultCharset());} catch (IOException ex) {throw new SystemException(FILE_READ_ERROR, ex);}}
  77. 77. もう一つ、便利なAPI
  78. 78. before
  79. 79. public class Entity {private int intValue;private long longValue;private float floatValue;private String string;private Date date;@Overridepublic int hashCode() {int result = intValue;result = 31 * result + (int) (longValue ^ (longValue >>> 32));result = 31 * result + (floatValue != +0.0f ? Float.floatToIntBits(floatValue) : 0);result = 31 * result + (string != null ? string.hashCode() : 0);result = 31 * result + (date != null ? date.hashCode() : 0);return result;}@Overridepublic boolean equals(Object o) {// 省略}}
  80. 80. public class Entity {private int intValue;private long longValue;private float floatValue;private String string;private Date date;@Overridepublic int hashCode() {int result = intValue;result = 31 * result + (int) (longValue ^ (longValue >>> 32));result = 31 * result + (floatValue != +0.0f ? Float.floatToIntBits(floatValue) : 0);result = 31 * result + (string != null ? string.hashCode() : 0);result = 31 * result + (date != null ? date.hashCode() : 0);return result;}@Overridepublic boolean equals(Object o) {// 省略}}自前で実装すると死ぬからだいたいIDEで自動生成
  81. 81. after
  82. 82. public class Entity {private int intValue;private long longValue;private float floatValue;private String string;private Date date;@Overridepublic int hashCode() {return Objects.hash(intValue, longValue, floatValue, string, date);}@Overridepublic boolean equals(Object o) {// 省略}}
  83. 83. public class Entity {private int intValue;private long longValue;private float floatValue;private String string;private Date date;@Overridepublic int hashCode() {return Objects.hash(intValue, longValue, floatValue, string, date);}@Overridepublic boolean equals(Object o) {// 省略}}JavaSE 7に新しく入ったObjectsのhashメソッドを利用
  84. 84. Java標準ライブラリもようやく整備されてきました
  85. 85. Lesson4 まとめNo J2SE 5.0 JavaSE 71 finallyでcloseする try-with-resources2 BufferedReaderでファイルを読み込む Files.readAllLines3Collectionの宣言は左辺にも右辺にも型名を記載するCollectionの宣言で右辺の型名は省略する4hashCodeの実装は、間違えないようにIDEで自動生成するhashCodeの実装はObjects.hashを使う
  86. 86. Final Lessonfrom JavaSE 7to JavaSE 8
  87. 87. JavaSE 8
  88. 88. Project LambdaStream interfaceDate and Time API... and more
  89. 89. before
  90. 90. private List<Record> resultList;public List<Record> getMoreThan(int min) {List<Record> newList = new ArrayList<>();for (Record record : resultList) {if (record.getScore() > min) {newList.add(record);}}Comparator<Record> comparator = new Comparator<Record>() {@Overridepublic int compare(Record o1, Record o2) {return o1.getScore() - o2.getScore();}};Collections.sort(newList, comparator);return newList;}
  91. 91. after
  92. 92. private List<Record> resultList;public List<Record> getMoreThan(int min) {List<Record> newList = resultList.stream().filter(record -> record.getScore() > min).sorted((o1, o2) -> o1.getScore() - o2.getScore()).collect(Collectors.toList());return newList;}
  93. 93. private List<Record> resultList;public List<Record> getMoreThan(int min) {List<Record> newList = resultList.stream().filter(record -> record.getScore() > min).sorted((o1, o2) -> o1.getScore() - o2.getScore()).collect(Collectors.toList());return newList;}Listのstream処理を開始filterで絞り込んで(引数はPredicate)sortedでソートして(引数はComparator)collectで結果を取り出して(引数はCollector)filterやsortedの条件をLambdaで記述
  94. 94. Lambda使いたくなったでしょ?
  95. 95. 検索:jdk8 download
  96. 96. いつ(略)いまで(略)
  97. 97. Final Lesson まとめNo JavaSE 7 JavaSE 81 単一メソッドの無名クラス Lambda
  98. 98. まとめ
  99. 99. 日経ソフトウエア2013年7月号の特集記事「そのコードは古い」のJava編を読んでね!購入:http://www.amazon.co.jp
  100. 100. 大事なことなのでもう一度
  101. 101. ENdoSnipeというOSSのJava解析・可視化ツールをぜひ使ってください!記事の検索:endosnipe gihyo公式サイト:http://www.endosnipe.com
  102. 102. To be continued !

×