Java challenge MethodReference
なにが出力される?
public static void main(String[] args) { List<Homer> homers = new ArrayList<>(); homers.add(new Homer()); homers.add(new Homer()); homers.add(new Homer()); homers.removeIf(e -> e.talk.equals("D'oh")); homers.forEach(System.out::println); } static class Homer { String talk = "D'oh!"; public String toString() { return talk; } }
考察
homers に3つの Homer インスタンスが格納された後、talk の内容を比較しているが、いずれも一致しないので除外はされないはず。
その後、println() にインスタンスを渡しただけで、toString() が呼び出される?とすれば、 D'oh! が3つ出力されるはず。
結果
D'oh!
D'oh!
D'oh!
println()メソッドが、渡されたインスタンスのtoString()メソッドを呼び出すということ。
割と基本的なことだったみたいですが、toString() を明示的に書くようにしていたので、勉強になりました。
Java challenge thread with lamda
何が出力されるのか?
public static void main(String[] args) throws InterruptedException { Runnable r = () -> { for(int i = 0; i <= 10000; i++) { System.out.println(i); } System.out.println("Running!"); }; Thread thread = new Thread(r); thread.start(); thread.join(); }
考察
Runnable r の定義が見慣れないのですが。
単純に考えると、つくられたスレッドの中で、i が 0 から 10000 まで出力された後、"Running!"が出力されて終わる気がします。
結果
0
1
2
3
....
9998
9999
10000
Running!
期待していた通りの出力でした。
たぶん、このチャレンジの意図は、Runnable r の定義の仕方なのかなと思います。
lamda であればこんな風に書けますよみたいな。
以下の記事のように、Runnable interface を実装する方法と比較すると、lamda を使った方が断然簡単に書けますね。
blueskyarea.hatenablog.com
Java challenge ListRemoveIf
何が出力されるのか?
public class ListRemoveIf { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(22); list.add(23); list.add(10); list.add(12); list.add(13); list.add(0); list.removeIf(e -> e == new Integer(12) || e.equals(new Integer(22))); System.out.println(list); } }
考察
これは、リストの要素を1つずつチェックして、もし12か22であれば、それを取り除こうとしているように見える。
でも、オブジェクト型(Integer)は == で比較は出来ないから、22だけが取り除かれると思われる。
結果
[23, 10, 12, 13, 0]
22だけが除外されました。
もし e == new Integer(12) の部分が e == 12 だったらどうなるか?
[23, 10, 13, 0]
結果は 12 も除外されました。
"-128から127"までの間の数値は、java内部で同一オブジェクトが使われるから、オブジェクトとして等しいという結果になっているようです。
Java challenge Interface
問題:何が出力されるのか?
public class BigBangTheory { public static void main(String[] args) { Scientist scientist = new Sheldon() { search() { System.out.println("This is my new spot!"); } }; scientist.search(); } interface Scientist { void search(); } static class Sheldon implements Scientist { void search() { System.out.println("This is my spot."); } } }
考え
Sheldon のインスタンス生成時に、search() をオーバーライドしているのだから
「This is my new spot!」と表示されるはず。
答え
コンパイルエラー。。理由↓
1. Sheldon クラス内の search() メソッドのアクセス修飾子の可視性が下がってしまっている。 public -> 指定なし
2. Sheldon のインスタンス生成時における search() メソッドに戻り値の型が指定されていない。
インターフェースのメンバは暗黙的に public になることと、文法の誤りに気付くかどうかですね。
コンパイル通るようにしたら、「This is my new spot!」が表示されました。
Java challenge Integer
問題:何が出力されるのか?
Integer number1 = 5; Integer number2 = 5; Integer number3 = 128; Integer number4 = 128; // True or False ? System.out.println(number1 == number2); System.out.println(number3 == number4);
考え
False, False が出力されるのかなと思いましたが、、、
True, False が出力されました。。
なぜ?
どうも、-128 から 127 は JREがキャッシュするらしく、同じ値が参照されるらしい。
パフォーマンス向上のため?
コード
Java/IntegerChallenge.java at master · blueskyarea/Java · GitHub
マルチスレッドプログラミング - Runnable interface の実装
前の記事では、Thread class を継承する方法を試しました。
マルチスレッドプログラミング - Thread class の継承 - 社内se × プログラマ × ビッグデータ
今回は、Runnable interface を実装することで、マルチスレッドを実現していきます。
こんな感じで作成できます。
public class Dog extends Animal implements Runnable { }
この実装のメリットとしては、継承するクラスの対象として、Thread クラス 以外を指定することができます。
Runnable インタフェースは、run() メソッドを実装しているので、オーバーライドします。
public class Dog extends Animal implements Runnable { @Override public void run() { // anything task } }
このスレッドを開始するためには、ワーカーとなるクラスのインスタンスを生成して、Threadインスタンスに渡してあげます。
そして、start() メソッドにより開始します。
Dog dog = new Dog(); Thread thread = new Thread(dog); thread.start();
Thread クラス自体が Runnable インタフェースを実装しています。
それと同じように Runnable インタフェースを実装したクラスを定義してあげていることになります。
Thread クラスに渡してあげることで、start() が使えるようになります。
public class Thread extends Object implements Runnable
まとめ
一つのスレッドを開始するために、最低2つのインスタンスを生成する必要がありますが、Thread 以外のクラスを継承できるのはいいですね。
マルチスレッドプログラミング - Thread class の継承
Apache spark などマルチスレッドのプログラミングを行う上で非常に便利なライブラリが登場していますが、それがあまりにも便利すぎるが故に、それ以前のマルチスレッドプログラミングについても学んでおきたいところです。
そもそも Apache spark のライブラリ自体が、内部的には元来のマルチスレッド手法を踏襲していたりもするところもあると思いますので、やはり知っておいた方が、より理解も深まるだろうと思います。
Java でマルチスレッドプログラミングを行う方法はいくつかあると思いますが、最も基本的な?ものは、Thread クラスを継承して使用するやり方かと思います。
Thread クラスを継承したクラスのインスタンスを生成し、start メソッドを実行することで、新たなスレッドを開始することができます。
以下はどこにでもありそうな簡単なサンプルです。
インスタンス生成時に渡された intervalMs の値 sleep するだけのスレッドです。
public class MyThread extends Thread { private long intervalMs; private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); public MyThread(long intervalMs) { this.intervalMs = intervalMs; } @Override public void run() { System.out.printf(dateFormat.format(new Date()) + " [%s] my-thread startging.\n", Thread.currentThread().toString()); try { Thread.sleep(intervalMs); } catch (InterruptedException ie) { // nothing to do } System.out.printf(dateFormat.format(new Date()) + " [%s] my-thread ending.\n", Thread.currentThread().toString()); } }
これを main メソッドから呼び出します。
5秒 sleep するスレッドと、10秒 sleep するスレッドを生成しています。
public static void main(String args[]) { SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); System.out.printf(dateFormat.format(new Date()) + " main thread at startging.\n", Thread.currentThread().toString()); MyThread myThread1 = new MyThread(5000); myThread1.start(); MyThread myThread2 = new MyThread(10000); myThread2.start(); System.out.printf(dateFormat.format(new Date()) + " main thread at ending, actually waiting my-thread ending.\n", Thread.currentThread().toString()); }
結果は以下のようになりました。
01:06:36 main thread at startging. 01:06:36 [Thread[Thread-0,5,main]] my-thread startging. 01:06:36 main thread at ending, actually waiting my-thread ending. 01:06:36 [Thread[Thread-1,5,main]] my-thread startging. 01:06:41 [Thread[Thread-0,5,main]] my-thread ending. 01:06:46 [Thread[Thread-1,5,main]] my-thread ending.
main スレッドは直ちに最後の行に到達していますが、スレッドは直ちに終了はせずに、すべての my-thread が終了するまで待ってくれています。
まとめ
1. Thread クラスを継承した独自のスレッド用のクラスを生成する。
2. run() 内に実際に実行させたい処理を書く。
3. start() でスレッド開始する。