102
from old Java to modern Java ~ 職業プログラマに聞いて欲しいJava再入門 Acroquest Technology株式会社 JJUG / 関西Javaエンジニアの会 谷本 心 ( @cero_t )

from old Java to modern Java

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: from old Java to modern Java

from old Javato modern Java

~ 職業プログラマに聞いて欲しいJava再入門

Acroquest Technology株式会社JJUG / 関西Javaエンジニアの会

谷本 心 ( @cero_t )

Page 2: from old Java to modern Java

自己紹介•職業:Javaトラブルシューター(教育もやってます)

•近況:gihyo.jpや日経ソフトウエアに記事を書きました

Page 3: from old Java to modern Java

ENdoSnipeというOSSのJava解析・可視化ツールをgihyo.jpで紹介しました

記事の検索: endosnipe gihyo

公式サイト: http://www.endosnipe.com

Page 4: from old Java to modern Java

日経ソフトウエア2013年7月号の特集記事「そのコードは古い」のJava編を執筆しました

同僚と一緒に「Javaのイケてるコード、残念なコード」を連載していました(4月号まで)

購入: http://www.amazon.co.jp

Page 5: from old Java to modern Java

本日のテーマ

イマドキのJava(文法編)

Page 6: from old Java to modern Java

Javaの文法の話

新しいAPIの話解析ツールの話バイトコードの話

Page 7: from old Java to modern Java

いま、現場ではどのバージョンの

Javaをお使いですか?(複数回答可)

Page 8: from old Java to modern Java

もちろんJavaSE7

Page 9: from old Java to modern Java

既にOracleのサポートが切れた

JavaSE6

Page 10: from old Java to modern Java

え、まだJ2SE 5.0ですか?

Page 11: from old Java to modern Java

まさかのJ2SE 1.4ですか?

Page 12: from old Java to modern Java

それより前?

Page 13: from old Java to modern Java

大丈夫です、今回は1.4や5.0あたりを

使っている人が一番のターゲットです

Page 14: from old Java to modern Java

逆にJavaSE8?

Page 15: from old Java to modern Java

すごいね、帰っていいよ!

Page 16: from old Java to modern Java

from old Javato modern Java

~ 職業プログラマに聞いて欲しいJava再入門

Acroquest Technology株式会社JJUG / 関西Javaエンジニアの会

谷本 心 ( @cero_t )

Page 17: from old Java to modern Java

Lesson1

Page 18: from old Java to modern Java

現場で見かけるこんなコード

Page 19: from old Java to modern Java

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; } }

Page 20: from old Java to modern Java

Lesson1

from “C-ish” Javato “Java like” Java

(J2SE1.4)

Page 21: from old Java to modern Java

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(); ...

Page 22: from old Java to modern Java

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が正常、それ以外が異常

Page 23: from old Java to modern Java

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;

Page 24: from old Java to modern Java

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;

Page 25: from old Java to modern Java

きちんとJava風に書き直すと・・・

Page 26: from old Java to modern Java

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; }

Page 27: from old Java to modern Java

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 ハンガリアン

Page 28: from old Java to modern Java

before / afterで見てみると

Page 29: from old Java to modern Java

before

Page 30: from old Java to modern Java

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; } }

Page 31: from old Java to modern Java

after

Page 32: from old Java to modern Java

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; }

Page 33: from old Java to modern Java

なんということでしょう

Page 34: from old Java to modern Java

No C-ish Java like

1メンバ変数は見やすいように

接頭辞をつけるメンバ変数はIDEが色をつけるから

接頭辞もthisも不要

2 スネークケース 文化的にキャメルケース

3変数は先頭で宣言しないと怒られるし

メモリ解放し忘れる変数は使っている場所が分かるよう

使う直前に宣言する

4関数の戻り値でエラーを表現

0を返せば正常エラーはExceptionで表現値が普通に返れば正常

5 引数に戻り値の参照を渡すと良いメソッドの引数はできるだけ変更しない

(特に戻り値がある場合)

Lesson1 まとめ

Page 35: from old Java to modern Java

Lesson2

from “J2SE 1.4”to “J2SE 5.0”

Page 36: from old Java to modern Java

ちなみに正式名称はJavaSE 5.0ではなくJ2SE 5.0らしいよ

Page 37: from old Java to modern Java

J2SE 5.0

Page 38: from old Java to modern Java

Generics foreach

enumstatic import

var args

auto boxing... and more

Page 39: from old Java to modern Java

イマドキのJavaのスタンダード

Page 40: from old Java to modern Java

before

Page 41: from old Java to modern Java

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; }

Page 42: from old Java to modern Java

after

Page 43: from old Java to modern Java

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; }

Page 44: from old Java to modern Java

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文)でシンプルに

ループ処理を行なう

Page 45: from old Java to modern Java

簡単すぎたのでもう一つ。

Page 46: from old Java to modern Java

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; }

Page 47: from old Java to modern Java

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; }}

Page 48: from old Java to modern Java

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; }}

定数インタフェースという優れたテクニック

定数クラス名を省略して記載できるんですよ!

Page 49: from old Java to modern Java

あると思います

Page 50: from old Java to modern Java

public enum ErrorCode { FILE_NOT_FOUND , FILE_READ_ERROR , FILE_EMPTY , RECORD_EMPTY , RECORD_SIZE_ERROR , RECORD_BODY_EMPTY , RECODE_CODE_NOT_NUMERIC; }

列挙するならenum

Page 51: from old Java to modern Java

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

Page 52: from old Java to modern Java

import staticが1つ以上あったら * になるようIDEを設定しておくと良い

Page 53: from old Java to modern Java

No J2SE 1.4 J2SE 5.0

1 Objectだけを扱うCollection Genericsを使ったCollection

2for (int i=0; i < list.size(); i++)

while (iterator.hasNext())for (String value : list)

3 定数インタフェースは便利 static importで定数を宣言する

4 int値を使ってコード一覧を作成 enumを使って列挙する

Lesson2 まとめ

Page 54: from old Java to modern Java

Lesson3

from “J2SE 5.0”to “JavaSE 6”

Page 55: from old Java to modern Java

JavaSE 6では、文法面はほとんど変化なし(ツール、APIの強化のみ)

Page 56: from old Java to modern Java

ちなみに、API変更のおかげでnative2asciiを使わなくて

済むようになったけど

Page 57: from old Java to modern Java

native2asciiを使う方が安全だから結局みんな使ってる(実際はIDEで変換)

Page 58: from old Java to modern Java

No J2SE 5.0 JavaSE 6

1native2asciiは面倒だからIDEの

プロパティファイル編集機能を使うnative2asciiは面倒だからIDEの

プロパティファイル編集機能を使う

Lesson3 まとめ

Page 59: from old Java to modern Java

Lesson4

from “JavaSE 6”to “JavaSE 7”

Page 60: from old Java to modern Java

JavaSE 7

Page 61: from old Java to modern Java

try-with-resources

diamond operatornio2

multi-catch... and more

Page 62: from old Java to modern Java

この辺からちょっと理解が

怪しくなる人が多い

Page 63: from old Java to modern Java

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; }

Page 64: from old Java to modern Java

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しないとリソースのクローズ漏れを起こして大変ですよね

別に起きないしいいよね

Page 65: from old Java to modern Java

敢えて言えば

Page 66: from old Java to modern Java

finallyでcloseするのは古い定石

Page 67: from old Java to modern Java

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; }

Page 68: from old Java to modern Java

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

Page 69: from old Java to modern Java

まぁファイル読むだけなら

Page 70: from old Java to modern Java

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); } }

Page 71: from old Java to modern Java

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のひとつ

Page 72: from old Java to modern Java

これでもうGroovyの人とかにプギャーされなくなる

Page 73: from old Java to modern Java

before

Page 74: from old Java to modern Java

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; }

Page 75: from old Java to modern Java

after

Page 76: from old Java to modern Java

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); } }

Page 77: from old Java to modern Java

もう一つ、便利なAPI

Page 78: from old Java to modern Java

before

Page 79: from old Java to modern Java

public class Entity { private int intValue; private long longValue; private float floatValue; private String string; private Date date;

@Override public 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; }

@Override public boolean equals(Object o) { // 省略 }}

Page 80: from old Java to modern Java

public class Entity { private int intValue; private long longValue; private float floatValue; private String string; private Date date;

@Override public 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; }

@Override public boolean equals(Object o) { // 省略 }}

自前で実装すると死ぬからだいたいIDEで自動生成

Page 81: from old Java to modern Java

after

Page 82: from old Java to modern Java

public class Entity { private int intValue; private long longValue; private float floatValue; private String string; private Date date;

@Override public int hashCode() { return Objects.hash(intValue, longValue, floatValue, string, date); }

@Override public boolean equals(Object o) { // 省略 }}

Page 83: from old Java to modern Java

public class Entity { private int intValue; private long longValue; private float floatValue; private String string; private Date date;

@Override public int hashCode() { return Objects.hash(intValue, longValue, floatValue, string, date); }

@Override public boolean equals(Object o) { // 省略 }}

JavaSE 7に新しく入ったObjectsのhashメソッドを利用

Page 84: from old Java to modern Java

Java標準ライブラリもようやく整備されてきました

Page 85: from old Java to modern Java

Lesson4 まとめNo J2SE 5.0 JavaSE 7

1 finallyでcloseする try-with-resources

2 BufferedReaderでファイルを読み込む Files.readAllLines

3Collectionの宣言は

左辺にも右辺にも型名を記載するCollectionの宣言で右辺の型名は省略する

4hashCodeの実装は、間違えないように

IDEで自動生成するhashCodeの実装はObjects.hashを使う

Page 86: from old Java to modern Java

Final Lesson

from “JavaSE 7”to “JavaSE 8”

Page 87: from old Java to modern Java

JavaSE 8

Page 88: from old Java to modern Java

Project Lambda

Stream interfaceDate and Time API

... and more

Page 89: from old Java to modern Java

before

Page 90: from old Java to modern Java

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>() { @Override public int compare(Record o1, Record o2) { return o1.getScore() - o2.getScore(); } };

Collections.sort(newList, comparator); return newList; }

Page 91: from old Java to modern Java

after

Page 92: from old Java to modern Java

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; }

Page 93: from old Java to modern Java

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で記述

Page 94: from old Java to modern Java

Lambda使いたくなったでしょ?

Page 95: from old Java to modern Java

検索:jdk8 download

Page 96: from old Java to modern Java

いつ(略)いまで(略)

Page 97: from old Java to modern Java

Final Lesson まとめNo JavaSE 7 JavaSE 8

1 単一メソッドの無名クラス Lambda

Page 98: from old Java to modern Java

まとめ

Page 99: from old Java to modern Java

日経ソフトウエア2013年7月号の特集記事「そのコードは古い」のJava編を読んでね!

購入: http://www.amazon.co.jp

Page 100: from old Java to modern Java

大事なことなのでもう一度

Page 101: from old Java to modern Java

ENdoSnipeというOSSのJava解析・可視化ツールをぜひ使ってください!

記事の検索: endosnipe gihyo

公式サイト: http://www.endosnipe.com

Page 102: from old Java to modern Java

To be continued !