しがない SE のホームページ

Summary

オブジェクト指向プログラミング言語「Java」
Javaは、新人研修からやり続けているので、1年と8ヶ月ほどやってます。
今、業務ではJavaEE7のjBatchを主に担当しています。

まだまだ知らないことが大量にあるので、頑張って勉強します。

memo

昔やった凡ミス(文字列操作編)

2017/12/18.


trim()やsubString()などで、文字の処理を行ったが、それを代入することを忘れた↓

String target = “Hello World”;
○target = Target.trim();
×target.trim();  //やっただけで満足すな!

BufferedReaderのmark()とreset()で、読み直しができる

2017/12/18.


reset()をすると、mark()をしている部分に戻って読み込みなおしてくれる。
実際は、mark()が実行されてから、reset()が実行されるまでの内容をバッファしてくれて、
バッファの内容を読んでいるような感じっぽい。

http://blog.mwsoft.jp/article/45580251.html

MANIFEST.MFの仕様書

2017/10/27.


MANIFEST.MFは、jarファイルの仕様とかを定める設定ファイル。

書き方とか、わからないなーと思ってドキュメントを探していたが、
文字が多くて、まったく読む気にならない以下のURLがそうらしい。
https://docs.oracle.com/javase/jp/8/docs/technotes/guides/jar/jar.html

jarファイルを実行する

2017/10/27.


jarファイルは、MANIFEST.MFにMainClassを設定することで、
jarファイルをダブルクリックするだけで、MainClassを実行することができる。

ちなみにコマンドだとこんな感じ↓
「java -jar jarファイル名」

プロンプト上で、「jarファイル名」の指定のみでも実行ができるが、
標準出力がされないので、注意。(ちょっと悩んだ)

サブクラスをスーパークラス型に代入する理由

2017/10/05.


インターフェースにある機能だけで十分である場合は、スーパークラス型で代入した方がよい
あとからの変更に耐えやすいということもあるのかも?

https://qiita.com/BumpeiShimada/items/da36bc98e140f2a4b9d1

変換指定子を用いて、ログに表示すべし!!!

2017/09/15.


たとえば、ログにファイルの情報を出すとする。
以下のように、+演算子でやらずに、変換指定子({})を利用した方がよい。
File file = new File("C:\\makiware", "test.txt");

logger.info("File → " + file.getName());// よろしくない

logger.info("File → {}", file.getName());// 望ましい

表示される文言は同じだが、
ログレベルをinfoではなく、warnに上げたりしたときに違いが出る。

ログレベルをwarnにしたとき、
+演算子で書いた方は、「file.getName()」の部分は評価される。(つまり、「file.getName」は実行される)
変換指定子({})で書いた方は、「file.getName()」の部分は評価されない。(つまり、「file.getName」は実行されない)

細かいことだが、微妙にパフォーマンスに差が出るのだ。
特にバッチ処理とかだと、こういった無駄が何億回も実行されることになり、
大きなロスになりうる。

これで私も違いのわかる男。

http://netbuffalo.doorblog.jp/archives/4466209.html

アノテーションの有効範囲

2017/08/29.


独自アノテーションを作るときに、
@Rentention(RententionPolicy.RUNTIME)やらつける。

そのときに、指定するポリシーに
SOURCE、COMPILE、RUNTIMEとある。

その使いどころ
SOURCE→@Overrideなどのコンパイル時のマーカー
COMPILE→謎
RUNTIME→実行時。バリデーションとか

http://www.ne.jp/asahi/hishidama/home/tech/java/annotation.html

ラムダの実態は、ただのメソッドの定義?

2017/08/25.



モックに置きかえたいオブジェクトは、フィールドに宣言する

2017/08/18.


モックに置きかえる場合は、
1.モックを作成する
2.モックをテスト対象クラスにセットする
3.モックの振る舞いを変更する
というステップが必要になる。

テスト対象クラスはテストメソッド実行のたびに、インスタンスが生成されるので、
モックは、テストメソッドの実行のたびに、テスト対象クラスにセットする必要がある

その際に、@Beforeのついたメソッドのなかで、ローカル変数のモックを作成して
セットしてもよいのだが、
この場合、各テストメソッドのなかで、モックの振る舞いを変更したい場合に、
テスト対象クラスのフィールドにあるモックに置きかえたオブジェクトを指定して、
振る舞いを変更しないといけない。

これだと、わかりづらい。
気がしません?

わかりやすくするには、
フィールドにモックに置きかえたオブジェクトを宣言した方がよい。

詳しくは、サンプルを。

単体テストの際に、モックで置き換えができるよう、protecetedにしておく

2017/08/18.


プレゼンテーション層
サービス層
業務ロジック層
Dao層
みたいなアーキテクチャーの場合、
プレゼンテーション層から、サービスを呼んで、サービスから業務ロジックを呼んで、
業務ロジックからDaoを呼んで、、という感じになる。

その場合、呼び出すものはすべてprotectedにしておくと、
単体テストの際に、モックで置き換えができて、楽。

privateにしちゃうと、セッターを用意してなくてはならなくて、めんどう。

なので、サービスやら業務ロジックやらの機能のインスタンスを生成する場合は、
アクセス修飾子を、protectedにしよう

人に説明しようとすると、ソースに疑問がたくさん生まれる

2017/08/17.


いま仕事で、チュートリアルを作成していて、
そのチュートリアルを先生として、説明するための準備をしてます。
内容としては、jBatchのことと、単体テスト(JUnit、Mockito)

チュートリアルは、自分ひとりで作っているわけではなくて、
3人で分担してます。

それで、先生をするのは、自分のみ。

なので、先生として説明をするために、他の人が作った資料を読み込んでいるわけなんですが、
説明しようと意識すると、たくさん疑問が生まれます。

例えば、
・なんでこれはフィールドにあるんだろうか?
・え、このコードは無駄じゃね?
・あれ、こうしないと動かないんかな?
などなど、、、

たぶん読んでいるだけ、動かしているだけじゃ、気付かなかったこと。
なんかJavaのセミナー(たぶんJJUG)行ったときに、
スピーカーが、「いいコードは、一行一行説明できること」
みたいなことを言ってたことを思い出した。

自分が書くときにも、
人に説明ができるよう、なんとなくではないコーディングをしようと思いました。

P.S ソースは書くよりも、読むほうの時間が多いので、丁寧に書きましょうということも
そのスピーカーは言ってたことも思いだした。

JUnitで、フィールドのインスタンスは毎回生成される

2017/08/17.


フィールドにテスト対象クラスをnewで生成するようなテストクラスがある。

XXXLogicTest {
    public XXXLogic target = new XXXLogic();

データを分割して処理する場合

2017/08/15.


データを分割して、処理をする場合、start(はじまり)とend(おわり)の指定が必要。
なにも考えず、だらーんと、よし分割処理できたと思うと、
おわりを指定しておらず、
1000のなにかを分割したときに
Aスレッドでは、0~1000(期待してたのは0~500)
Bスレッドでは、500~1000
の処理をしていたみたいなことがあった。

おっちょこちょいの人は気をつけた方がよさげ(自戒)

jBatchのpartitionまとめ

2017/08/10.


jBatchのpartitionは、ステップを多重化することができる。
その方法は、
①plan要素を用いた静的なpartition
②mapper要素を用いた動的なpartition

planは、JSLに何多重化するかをハードコードする。
mapperは、入力の行数やサイズによって、何多重化するかをプログラムを組んで、動的に決められる。

partitoinの動作まとめ
・ステップリスナーは、partitionごとに実行されない。(つまり一度のみ)
・ステップリスナーのafterStep()が呼ばれるタイミングはすべてpartitionごとの処理が終わってから
・partitionごとにスレッドができて、それぞれインスタンスが生成される
・planのpartition属性は、配列のようになっていて、0からスタートさせないといけない
・mapperの場合、beforeStepのあとにPartitionMapperがインスタンス化され、mapPartitions()が実行される
・stepContext、jobContextのインスタンスはpartitionごとにそれぞれ作られる

オブジェクトの配列

2017/08/09.


Stringとかintとかの配列はまあできる。
普通のオブジェクトの配列を作るときどうやるんだっけ?
ってちょい手間取った。

Properties prop[] = new Properties[2];

なんか見慣れない書き方だなあ、と

privateなコンストラクタを網羅する

2017/08/04.


以下の方法でprivateなコンストラクタをテストで実行できる
Constructor<?> constructors = XXX.class.getDeclaredConstructors();
// アクセスできるようにしてる
constructors[0].setAccessible(true);
Object obj = null;

try {
	obj = constructors[0].newInstance();
} catch(Exception e) {
	Assert.fail("コンストラクタの網羅で異常終了");
}
// インスタンスがnullでないかの確認
Assert.assertNotNull("コンストラクタ実行結果がnull",obj);

コンストラクタが複数定義されたらどうなるのかは不明(今度、覚えてたら調べる)

PrintWriterは内部でBufferedWriterをラップしている

2017/08/01.


詳細はまたあとで

PrintWriterは例外が発生しえない

2017/08/01.


BufferedWriterとかだと、try句で囲って、finallyでcloseしないといけないが、
PrintWriterのメソッドは例外を発生させないのでfinallyでやる必要がない

PrintWriter pw = new PrintWriter(new File("HOGEHOGE.txt"));
pw.println("FOOBAR");
pw.flush();
pw.close();

みたいな感じ。
IOExceptionが起きたらonCheckError()を使うみたいだが、どういう風に使うのが正解なのだろうか、、、

文字コードを指定して、BufferedWriterのインスタンスを生成する

2017/07/31.


BufferedWriter bw = null;
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("HOGEHOGE.txt")),"UTF-8"));

結構忘れがちなので。
PrintWriterを使っちゃえばいいんだけどねー。

privateなフィールドをリフレクションで参照する

2017/07/31.


テストとかで、どうしてもprivateなフィールド(getter/setterもない)にアクセスする必要がある場合が出てくる。
その場合、リフレクションを使うと解決ができる

詳しくはサンプルを確認できるが、
忘れがちなのが、field.setAccessible(true);としないとアクセスができない点。

JVMを監視する

2017/07/04.


たとえば、なにかしらを動かしてるときに、
突然落ちたりする。
なんで落ちるんだろ、メモリかな?とか

なんでこの処理遅いんだろ~とか調べるときに、
目盛やCPUの利用率をみて、アプリ側の処理でコストがかかってるのか
それとも、SQLの発行や他システムとの通信で遅いのかをある程度判断ができる

とか


メモリやCPUがどういう風に推移しているかを、
JVMを監視して、確認することができる。

#Javaのプロセスを表示する
ps -aux | grep java

#Javaのプロセス表示からIDを確認し、topコマンドでそのプロセスを監視する
top -p プロセスID


これでメモリだったり、CPUの稼働率などを確認することができる

文字コードを指定してファイルの操作を行う

2017/06/27.


reader
		BufferedReader br = null;
		File file = new File("XXX.txt");
		FileInputStream fis = new FileInputStream(file);
		InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
		br = new BufferedReader(isr);

writer(追記型)
		PrintWriter pr = null;
		File file = new File("YYY.txt");
		FileOutputStream fos = new FileOutputStream(file);
		OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
		pw = new PrintWriter(osw);

めんどい、、、

大量データを扱う場合、ListよりHashSetの方がめちゃ早い

2017/06/21.


http://d.hatena.ne.jp/greennoah/20090114/1231936654
コレクションのcontainメソッドとか使って検索する場合があったりするよね
その場合HashSetの方がArrayListより早い

なぜかというと、HashSetはハッシュ値によって、検索がかかる。
そのため、一発でみつかる

ArrayListの場合、先頭から順に要素を取り出して比較するために、
大量データの場合は時間がかかってしまう

実行クラスのクラス名を取得する

2017/06/20.


以下のようにして、実行クラスのクラス名を取得できる
たとえば、JUnitでテストする際にテストしているクラスを表示したりするのに利用する

this.getClass().getSimpleName();