${ 自分のための技術ナレッジ }

自分のための技術メモです

|Java| StreamAPI アトミックでない処理での注意

下記の処理は結果が実行毎に異なる。

parallel()により並列でラムダ式内の処理が実行されるが、インクリメント/デクリメントがアトミックで無いため足し引きのタイミングによって結果(p.x)が異なってしまう。

import java.util.stream.IntStream;

public class Test01 {

	public static void main(String[] args) {

		Person p1 = new Person();

		IntStream.range(0, 100000).parallel().forEach(i -> {
			if (i % 2 == 0) { p1.x++; } else { p1.x--;} ;
		});
		System.out.println(p1.x); // 結果がランダム

		Person p2 = new Person();
		IntStream.range(0, 100000).parallel().forEach(i -> {
			if (i % 2 == 0) { p2.inc(); } else { p2.dec();} ;
		});
		System.out.println(p2.x); // 結果は常にゼロ
	}

}

class Person {
	int x;

	synchronized void inc() {
		x++;
	}

	synchronized void dec() {
		x--;
	}
}

|Java| Java7 Gold 取得に向けてメモ

忘れそうな事柄をメモ

列挙型

イニシャライザの呼び出し順序

super……親クラス
sub……子クラス
static { } …… static イニシャライザ
{ } …… イニシャライザ
() …… コンストラクタ

  1. super static { }
  2. sub static { }
  3. super { }
  4. super ()
  5. sub { }
  6. sub ()
  7. super { }
  8. super ()
  9. sub { }
  10. sub ()

可変長引数

  • メソッド呼出時の引数が明確なメソッドが優先的に実行される.
// x.method(1, 2); の場合
void method(int... a) {}
void method(int a, int b) {} // こっちが実行される
  • 引数に null
// m(null);
public static void m(int... ary) {
	System.out.println(ary);
} // 正常にコンパイル -> null

public static void m(String... ary) {
	System.out.println(ary);
} // コンパイルで警告 -> null

タイプ null の引数は、タイプ InitializerSub からの
可変引数メソッド m(String...) の呼び出しに対しては String[] へ
明示的にキャストする必要があります。
あるいは、可変引数呼び出しに対しては String へキャストすることもできます

→回避するには、m((String) null); or m((String[]) null);

|Java| フレームワーク選別

随時、追記していきます。
2015/05/24 現在、自分の中での組み合わせは
SpringMVC + Spring4 + DBFlute + Lombok + Thymeleaf
です。(但し、SpringMVC周りは拡張)

(自分の中で) 有用なフレームワーク

フロント・コントローラ周り
  • SpringMVC …… 現時点での最有力。拡張はSAStrutsの方がし易い。
  • SAStruts …… 拡張し易いので大規模PJにも向いている。現在は更新が停止しているため新規PJでは見送る可能性大。
  • SAFlute …… SAStruts拡張。現在でも更新されているため新規PJでも候補として有り。
  • JSP …… EL式、ELファンクション、カスタムタグ、タグファイルを利用すれば、結構スッキリ記述できる。現在はThymeleafの方が有力。
  • Thymeleaf …… SAStruts, SpringMVCとも連携可能。
DI
  • Seasar2 …… 現時点での最有力。
ORM・DB周り
  • S2JDBC …… 現時点での最有力。
  • DBFlute …… 自分の中でS2JDBCに取って代わろうとしている。ORM以外のツールとしての利用でも期待大。
その他
  • Lombok …… コード中のボイラープレート(冗長な記述)を排除できる。

(自分の中で) 今後使ってみたい、興味のあるフレームワーク

テンプレートエンジン
フロント・コントローラ周り
  • Play Framework …… フロントに限らないフルスタック。大規模PJでも使えるか、まだ判断できないので見送り中

(自分の中で) 使いたくないフレームワーク

フロント・コントローラ周り
  • Struts …… 今更という感じ
  • Struts2 …… SAStrutsと比べて利点が見えない。アノテーションによる遷移設定などが冗長過ぎる。
  • Teeda …… 自由度が低い。(繰り返しで id が重複する、aタグで do が呼び出せないなど、その他多数の不満点)
  • S2Click(Click) …… 更新が無いようなので見送り中
DI
  • Guice …… Seasar2より優位点があれば使いたいが、今のところ保留中。
ORM・DB周り
  • Spring JDBC …… 古いVerしか知らないけど、ほとんど生のJDBCと同じだった。
  • S2Dao …… 悪くはないけど、それなら S2JDBCDBFlute を使いたい。また、Dao層はIFのみとなるため、Dao層でDB取得結果を加工して返すなどの処理が行えない。
  • iBatis(MyBatis) …… 悪くはないけど、それなら S2JDBCDBFlute を使いたい。やっぱり今時は2WaySQLが使えないのはつらい。

(自分の中で) 使ったことないけど、今後も使いたくないフレームワーク

ORM・DB周り
  • Hibernate …… これを使ってるプロジェクトで燃えないプロジェクトを知らない。

|JavaScript| コーディング規約

1. 「==」は使わず「===」を使う

[改善前]
var a = 1;
var b = "1";
if (a == b) {
	// 暗黙の型変換が行われるため、通る
}
[改善後]
var a = 1;
var b = "1";
if (a === b) {
	// 暗黙の型変換が行われないため、通らない
}

暗黙の型変換に頼らず、型を合わせるときは明示的に型変換をすること。

2. 変数の宣言には必ず「var」を利用する

[改善前]
a = 1;
[改善後]
var a = 1;

暗黙の変数定義はグローバル変数となる。グローバル変数は悪と考え、変数の定義は全て「var」を利用すること。(また、strict モードでは改善前のコードは「Uncaught ReferenceError: a is not defined」となり利用できない。)

3. 早期リターン

[改善前]
function func(x) {
	if (x === 1) {
		// ここに処理
	}
}
[改善後]
function func(x) {
	if (x !== 1) {
		return;
	}
	// ここに処理
}

インデントが深いと見づらい。ので、特定条件の場合に処理をするのではなく、その反対の条件で早期にリターンし、その後に処理を記述する。

4. 子コンストラクタでは親コンストラクタを呼ぶ、かつprototypeに親を紐付けること

[改善前]
function Animal(x) {
	this.x = x;
}
function Person(h, w) {
	this.h = h;
	this.w = w;
}
Person.prototype = new Animal(10); // 継承時点で値が必要
[改善後]
function Animal(x) {
	this.x = x;
}
function Person(x, h, w) {
	Animal.call(this, x);
	this.h = h;
	this.w = w;
}
Person.prototype = Object.create(Animal.prototype);

|Java| コーディング規約

自分の中でのコーディング規約を追記していきます。
一般的なコーディング規約(boolean は is にしろなど)は省きます。

1. setter より getter

[改善前]
public int x;

public void process() {
	setXxx();
}
public void setXxx() {
	this.x = x * x * x;
}
[改善後]
public int x;

public void process() {
	this.x = getXxx();
}
public void getXxx(int x) {
	return x * x * x;
}

フィールドに対して業務処理結果を、メソッド内部で代入(setter)するのではなく、処理結果を呼び出し元で受け取り(getter)代入する。
複雑なシステムになると、呼び出したメソッド内でいつの間にか状態が変わり、バグの温床となる。