JavaSilverの感想~Javaはオブジェクト指向と関数型言語の2つの性格を持つ
JavaSilverに合格できたので、気づきをメモ。
【参考】
Java SE 11 Programmer I (1Z0-815-JPN) 試験 | Oracle University
Javaメモ目次(Hishidama's Java Memo)
Java新機能メモ(Hishidama's Java up-to-date)
【1】僕はJavaは好きだ。
Javaを習得した後、オブジェクト指向設計やUML、RUPを知りたくなって、開発プロセスの奥深さを学ぶことができた。
オブジェクト指向の考え方を学ぶならJavaはお勧めだと思う。
一方、Java SE11で書いてみると、Javaはオブジェクト指向言語というよりも関数型言語になろうとしている気がする。
実際、ラムダ式やvar、型推論などは関数型言語の特徴をJavaに取り入れている。
Javaに新しくストリームAPIとは何だろう?と思っていたら、何のことはない、MapReduceのAPIに過ぎない。
つまり、関数型言語の特徴を取り入れて並列処理を意識しているわけだ。
そんなことを思うと、Javaはオブジェクト指向言語と関数型言語の2つの性格を持つように進化したのだろうと思う。
以前のJavaから追加された主な文法、機能をメモしておく。
・ module-info.java (exports パッケージ, requires モジュール)
・ javaコマンドのソースファイルモードで直接実行
・ jmod, jdeps
・ アノテーション
・ ラムダ式
・ インターフェースのdefaultメソッド、privateメソッド
・ var型
・ try-with-resources 構文
・ オートボクシング
・ ジェネリクス
・ 可変長引数
・ 共変戻り値によるオーバーライド
・ ストリームAPI=MapReduce用API
・拡張for文
Javaで気づいたことをメモしておく。
【2】Javaのvarについて
varを使えば、わざわざ変数の型宣言はしなくていい。
ただし、型が判定できるような初期値でなくてはいけない。
Java varメモ(Hishidama's Java var Memo)
しかし、varを取り入れることで、今までのJavaの文法や考え方が複雑化していると思う。
たとえば、Javaにはジェネリクスがある。
さらに、ダイアモンド演算子によって、ジェネリクスの型宣言を短く書けるようになった。
ダイアモンド演算子は右辺の型引数を省略(推論)するが、varは左辺の型を推論するから、両方を組み合わせるとややこしくなる。
変数の定義方法の変遷 Java varメモ(Hishidama's Java var Memo)
(引用開始)
ダイアモンド演算子は、右辺の型引数を省略(推論)するものである。
一方、varは左辺の型を省略(推論)するものなので、ダイアモンド演算子とは相性が悪い。
つまり「var map = new HashMap<>();」と書いたら、変数が何の型なのか分からない^^;
(実際に書くと、HashMap
【3】自動ボクシング
プリミティブ型とラッパークラスを同一視して代入できるようになった。
自動ボクシングのおかげで、プリミティブ型はオブジェクトっぽく考えられるかな。
自動ボクシング Java型メモ(Hishidama's Java type Memo)
しかし、オーバーライドする時に、int[]という配列はObject型とみなす場合がある時は正直迷った。
【4】拡張for文
RubyやPythonのようなfor文を書くことができる。
ループ処理の文法は、while→for文→拡張for文→List.forEach()へと進化しているが、過去の文法が残っているのでややこしく感じてしまう。
for each(拡張for文) Java文メモ(Hishidama's Java Statement Memo)
【5】Javaは実行時のインスタンスのメソッドが呼ばれる
Rubyと違って、Javaは実行時のインスタンスのメソッドが呼ばれる。
C++のvirtualメソッドと同じ。
つまり、Javaでは、クラスやインスタンスは、型に強く紐づく。
型は、フライパンのタイヤキの型に例えられる。
実行時のインスタンスのクラスが重要 裏Javaメモ(Hishidama's Java Memo)
この性質を使えば、ポリモルフィズムによって、実行時に動的にインスタンスを切り替えて、同一のメソッドで処理を入れ替えられる。
【6】同一クラス内の同一変数名、同一ローカル変数
(引用開始)
変数名やメソッド名に同じ名前を使える箇所がある。同じ名前が使えない箇所もある。
(引用終了)
重複する名前、同一クラス内の同一変数名、同一ローカル変数 裏Javaメモ(Hishidama's Java Memo)
メソッド内で、フィールドと引数が同じ変数名の場合、thisを使っていないとローカル変数とみなされる。
Eclipseでは、変数名が色付けされるのでフィールドなのか、ローカル変数なのか、区別できるが、エディタ上では判別できない。
普通は、潜在バグになるので、こういう紛らわしい変数名を付けないと思う。
【7】アクセス制御
Javaのアクセス制御は普通の考え方でいい。
注意点は、public/protected/privateのような修飾子がない場合は、同一パッケージ内でしか呼び出しできないこと。
アクセス制御 Javaクラス定義メモ(Hishidama's Java Class define Memo)
下記のような変な書き方もできるが、普通はしないだろう。
スーパークラスを呼ぶだけのオーバーライド 裏Javaメモ(Hishidama's Java Memo)
【8】ラムダ式は無名内部クラス(匿名クラス)を短く記述できる記法
Javaのラムダ式は、Rubyのクロージャを知っていればすぐに理解できるだろう。
一方、Javaの観点では、ラムダ式は無名の内部クラスで冗長に書き換えられる。
Javaラムダ式メモ(Hishidama's Java8 Lambda Expression Memo)
ラムダ式の注意点は、「ラムダ式内部で外側の変数を使う場合は、その変数はfinalもしくは実質的finalでなければならない。」
つまり、「ラムダ式の外側で定義されている変数を、ラムダ式内部から参照することが出来る」が、書き換えは不可。
コンパイルエラーになる。
RubyやPythonのレキシカルスコープとは異なる。
【9】リソース付きtry文
Javaでも、例外をキャッチしたらリソースClose→finallyが簡便に書けるようになった。
Rubyのbegin~rescue~ensureと似てる。
リソース付きtry文 Java文メモ(Hishidama's Java Statement Memo)
リソース付きtry文が無い頃は、finallyの中でさらに、try~catchをわざわざ書いていた。
Release It! 本番用ソフトウェア製品の設計とデプロイのためににも、それを書かなかった場合の本番障害の事例が書かれていた。
| 固定リンク
「プログラミング」カテゴリの記事
- Javaのモジュールシステムの考え方をまとめてみた(2022.10.21)
- Javaのモジュールシステムは複雑性をより増している(2022.09.10)
- Javaはなぜ関数型言語になろうとしているのか(2022.09.02)
- Javaのラムダ式の考え方(2022.08.10)
- Javaはオブジェクト指向言語ではなく関数型言語だった~「[増補改訂]関数プログラミング実践入門」はお勧めの本だ(2022.08.06)
コメント