Javaな部屋

概要
ここではJavaに関して学んだこと身に付けたことを記載したいと思います。
Java5.0、Spring、iBatis、struts、JavaEE5など記載していく予定です。

目次

Ibatorの利用方法
JavaSE5でのアノテーションの使い方
リファクタリング

JavaSE5でのアノテーションの使い方

ここではJavaSE5でのアノテーションの使い方を説明しています。
アノテーションの自作方法、アノテーションの種類、アノテーションの取得方法を説明します。
またアノテーションの簡単な使用例も示します

目次
アノテーション作り方
アノテーションの付与方法
アノテーションの種類
アノテーションの取得方法
アノテーションの活用例

アノテーション作り方

アノテーションは以下のように作成します。
public @interface Marker {}
簡単ですね!
アノテーションは値を持つものと持たないものを作成できます。
値を持たないアノテーション(上記)を、マーカーアノテーションとも言ったりします。
値を持つアノテーションの作り方は以下のように行います。
なお{default "nothing"}は、値を指定されなかったときに設定するデフォルト値です。
defaultを付けることで、アノテーション使用時に値の指定を非必須と出来ます。
public @interface SingleValue {
	String value() default "nothing";
}
アノテーションには複数の値を保持させることも出来ます。
複数の値を保持させたアノテーションの例は以下です。
public @interface MultiValue {
	String[] values();
	int amount();
}

アノテーションの付与方法

アノテーションの使い方は、JavaSE5以上のJavaを使っている方はなれているかと思いますが、説明します。
アノテーションは以下の場所に付与することが出来ます。
パッケージ、型宣言(classとかinterfaceとか)、フィールド、メソッド/コンストラクタ、メソッド引数、ローカル変数。
以下は使用例です。
@Marker //クラス
class AnnotationSample{
	@Marker
	AnnotationSample(){} //コンストラクタ
	
	@Marker
	String word; //フィールド
	
	@Marker
	void doSomething(){} //メソッド
}
マーカーアノテーション以外で、値を持つアノテーションの付与方法は以下のようにします。
class AnnotationUser {	
	@SingleValue("Hello")
	public void doSingleValue(){}
	
	@MultiValue(values={"Japan","Chiba"},amount=100)
	public AnnotationUser() {}
}
値を1つしか持たないアノテーションは、アノテーションのどのフィールドに代入するかを指定しなくてもいいんですね。
値を複数持つアノテーションは、フィールド名=値 の形をとります。

アノテーションの種類

独自アノテーションに対して、既存のアノテーションを指定することで振る舞いを指定することが出来ます
振る舞いを指定できるアノテーションをいくつか紹介します。

Target指定

Target指定は、アノテーションを付与できる場所を限定します。
Targetは、以下のように使用します。Targetの付与複数の場所指定も可能です。
なお、Target指定を行わない場合、全ての場所に対してアノテーションを付加できます。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.ANNOTATION_TYPE)
@interface MetaTargetAnnotation {}

@Target(ElementType.CONSTRUCTOR)
@interface MetaTargetConstructor {}

@Target(ElementType.FIELD)
@interface MetaTargetField {}

@Target(ElementType.LOCAL_VARIABLE)
@interface MetaTargetLocalValue {}

@Target(ElementType.METHOD)
@interface MetaTargetMethod {}

@Target(ElementType.PACKAGE)
@interface MetaTargetPackage {}

@Target(ElementType.PARAMETER)
@interface MetaTargetParameter {}

@Target(ElementType.TYPE)
@interface MetaTargetType {}

@Target({ElementType.METHOD,ElementType.FIELD})
@interface MetaTargetMulti {}

Retention

Retentionアノテーションは、付与したアノテーション情報をいつまで保持するかを指定するアノテーションです。
Retentionでは、{ソース、クラス、ランタイム}の3種類の指定が可能です。
指定したそれぞれの状態までアノテーション情報を保持できます。
以下が使用例です。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.SOURCE)
@interface MetaRetentionSource{}

@Retention(RetentionPolicy.CLASS)
@interface MetaRetentionClass{}

@Retention(RetentionPolicy.RUNTIME)
@interface MetaRetentionRuntime{}

Inherited

Inheritedアノテーションは、継承したクラスでもアノテーション付加状態を保持することの出来るアノテーションです。
わかりにくいので、使用例を示します。
import java.lang.annotation.Inherited;

@Inherited
public @interface MetaInheritedAnnotation {}

@MetaInheritedAnnotation
class AbstractSample{}

class Sample extends AbstractSample{}
この場合、Sampleクラスにも@MetaInheritedAnotationが付加された状態と同じになります。

アノテーションの取得方法

独自アノテーションを作って、付与して終わりでは意味がありません。
次は付与した独自アノテーションを取得する方法を示します。
アノテーションを取得する場合には、リフレクションを使用します。
リフレクションでは、クラス、フィールド、メソッドなどにアクセスでき、それらを利用して付与されたアノテーションを取得します。
以下は、クラスに付与されたアノテーションを取得する例です。
package com.yoheim.java5.main;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface Marker{}

@Retention(RetentionPolicy.RUNTIME)
@interface SingleValue{
	String value() default "nothing";
}

@Marker
@SingleValue("something")
public class GetAnnotation {

	public static void main(String[] args){
		
		//全てのアノテーションを取得
		GetAnnotation me = new GetAnnotation(); 
		Annotation[] ans = me.getClass().getAnnotations();
		for (Annotation an : ans) {
			System.out.println("Annotation: " + an);
		}
		
		//指定したアノテーションを取得
		Annotation annotation = me.getClass().getAnnotation(SingleValue.class);
		SingleValue single = (SingleValue) annotation;
		//アノテーションの中身を取り出す
		System.out.println("SingleValue: " + single.value());
	}
}
コーディングのお作法的にはよくないとこもありますが、それはご勘弁を。
上記のようにアノテーションを取得します。
アノテーションを全て取得する方法や、指定したアノテーションを取得する方法などあります。

アノテーションの活用例

アノテーションを利用した簡単な使用例を示します。
以下の例は、ユーザ情報でアノテーションの付与されている情報に対して、必須チェックを行う例です。
ユーザ情報を取得してきて、その情報で必須チェックを行うべき場所をアノテーションの有無で特定します。
必須チェックを示すアノテーションの付与されたフィールドは、nullでないかをチェックします。
チェックに問題がある場合には例外通知を行い、問題ない場合には、最終的に"OK"と出力します。
コーディングお作法として問題な点もありますが、ご勘弁くださいな。
package com.yoheim.java5.main;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;

@Retention(RetentionPolicy.RUNTIME)
@interface CheckRequired{} //必須チェックを示すアノテーション

class User{
	@CheckRequired
	String id;

	@CheckRequired
	String name;
	
	String address;

	//getter・setterは省略
}

public class AnnoationUsingSamle {

	public static void main(String[] args) throws Exception {
		
		User user = getUser();
		checkUserInfo(user);
		System.out.println("OK");
	}

	//必須チェックを行う場所
	private static void checkUserInfo(User user) throws Exception {
		Field[] fields = user.getClass().getDeclaredFields();
		for (Field field : fields) {
			CheckRequired cr = field.getAnnotation(CheckRequired.class);
			if(cr != null){
				//必須チェック
				if(field.get(user) == null)
					throw new IllegalStateException();
			}
		}
	}

	private static User getUser() {
		User user = new User();
		user.id = "001";
		//user.name = "yoheim"; //必須のnameを指定しない。→checkに引っかかる。
		user.address = "Japan";
		return user;
	}
}
TOPへ


リファクタリング~美しいプログラムに向けて~

ここでは美しいプログラムを書くという目標のため、リファクタリングについて記述します。
美しいかどうかは、人によりけりかと思いますが。。。
ここでの美しいとは、読みやすいコード/保守しやすいコードという意味で仮に定義したいと思います。

条件のメソッド化
条件式内の条件をメソッド化し、分かりやすくする。
以下の例は、引数dateの日付によって、支払う給与を判定するロジックです。
夏季期間ならば夏のボーナス、それ以外ならば冬のボーナスをaddして給与を支払います。

《前》
if(date.before(SUMMER_TIME_START) || date.after(SUMMER_TIME_END))
return _salary + _winterBounus;
else
return _salary + _summerBounus;
《後》
if (notSummerTime(date))
return _salary + _winterBounus;
else
return _salary + _summerBounus;
・・・
private boolean notSummerTime(date) {
return date.before(SUMMER_TIME_START) || date.after(SUMMER_TIME_END);
}
inserted by FC2 system