はてなインターンの事前課題で非常に簡単なltsvパーサーを作るやつがあるのだけど、Javaの勉強のためにJavaで実装してみた。ltsvパーサーは結構いろんな言語で誰かが実装しているので、これどうするのがいいのかってなったら、その実装を見に行くとやり方を理解できて便利。
- 事前課題 https://github.com/hatena/Hatena-Intern-Exercise2015
- やったやつ https://github.com/shibayu36/java-Intern-Exercise
これでいいのか気になるところもあるので、詳しい人に添削されたい。
- 日付操作こんなのでいいのか
- ファイル読み込みからLtsvLogクラスに変換するところ、もうちょっとクールに書けないか
- テストで正しく例外が上がってきているか確認するところ
いろいろ勉強になったので、勉強になったことを書いておく。
日付操作
http://qiita.com/tag1216/items/91a471b33f383981bfaa あたりが参考になった。しかしなかなか使うのが難しい。
epoch秒から文字列で出力するのはこんな感じ?こんなのでいいのか気になる。
LocalDateTime dt = LocalDateTime.ofInstant(Instant.ofEpochMilli(123456789000), ZoneId.of("UTC")); DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); System.out.println(dt.format(f));
コレクション操作
ArrayとかListとか、Mapとかのコレクション操作を学べた。Javadocとか見ても全然よくわからなかったけど、https://github.com/tokuhirom/java-handbook のCollectionsの説明が分かりやすくて助かった。
最近はListをstreamに変換して、mapとかいろいろやって、Listに戻すみたいなのが簡単にできるようになったみたいで便利。
ファイル読み込み
歴史的経緯とかがいろいろあって、どうやるのがいいのか最初全くわからなかった。それで、Javaで1行ずつテキストデータを読み込むイディオムの変遷 - argius note の記事が参考になって、ようやくできるようになった。
- try with resourcesによる自動close機能
- Streamとラムダ式を使った読み込み
辺りの勉強になった。以下全行をリストで読み込む例。もうちょっといい方法あるのかな。
List<String> lines; try (Stream<String> stream = Files.lines(Paths.get("path/to/file.txt"))) { lines = stream.collect(Collectors.toList()); } catch (IOException e) { throw e; }
例外の処理
LtsvParserを作るにあたって、
- 存在しないファイルを渡した時
- ltsvとしてパースできなかった時
に、どのようにエラーを返すか迷った。Golangだったらerrを返したり、ScalaだったらEitherを返したり、Perlだったらdieしたり、いろんな方法がある。Javaだったらどうするんだろうと。
見てみるとJavaはThrowableの文化っぽい雰囲気を感じた。そうすると今度はException, RuntimeException, Errorっていうのがあって、どう使い分ければ良いのか分からないという感じになる。
参考になったのは Throwableについて本気出して考えてみた - 都元ダイスケ IT-PRESS 。これによると、以下のようにまとめられていた。
これを読んで、LtsvParserの例で、存在しないファイルを渡した時とltsvとしてパースできなかった時にはExceptionかRuntimeExceptionをthrowすれば良さそう。じゃあどっちをthrowしたらいいのか。
どっちを使う可能性もあるけど、今回はLtsvParserには存在していてltsvでパースできるファイルパスを必ず渡さなければならないという仕様にしたいと考えたため、RuntimeExceptionをthrowすれば良さそうということになった。
ではException(チェック例外?)はどのような時にthrowするのかって考えてみたけど、例えば
- Webアプリケーションで、ブログ記事を作成する機能を考える
- ブログ記事はタイトルが1文字以上100文字以下、コンテンツが1文字以上必要とする
- ブログ記事を作成するControllerがあって、そのControllerは単にブログ記事を作成するロジックBlogEntryLogic.postEntry(String title, String content)を呼ぶとする
- BlogEntryLogic.postEntry内でtitleが1文字以上100文字以下でなければBlogEntryTitleLengthException, bodyが1文字以上でなければBlogEntryContentLengthExceptionをチェック例外として投げる
- Controllerはその例外を受け取って、最終的にユーザーの画面にどのようなフィードバックを返すか決める
みたいな使い方をするかなと思った。この辺詳しく触れるとバリデーションをどこでするか問題とかにもぶち当たって説明が面倒なので、詳しくは書かない。
まとめ
はてなインターンの事前課題は、日付・コレクション操作・テスト・ファイル・例外処理が一通り学べていい題材だと思った。