Java開発メモ

Java開発についてのメモ書きです。

基本

文字列

オブジェクトを文字列へ変換(Apache Commons Lang)

String str1 = new ReflectionToStringBuilder(this).toString();
String str2 = ToStringBuilder.reflectionToString(this);

コレクション各要素処理

コレクションの全要素をそれぞれ処理する。

Java1.4の場合は、イテレータを使用する。

Iterator ite = list.iterator();
while (ite.hasNext()) {
	String str = (String) ite.next();
	System.out.println(str);
}

Java5の場合は、拡張for文が使える。

for (String e : list) {
	System.out.println(e);
}

Java8の場合は、ラムダ式が使える。

// ラムダ式
list.forEach((str) -> {
	System.out.println(str);
});
// ラムダ式にメソッド参照を渡す。
list.forEach(System.out::println);

入出力ストリーム

String→InputStream変換

InputStream is = new ByteArrayInputStream("Hello".getBytes("UTF-8"));

実行中のメソッド名取得

実行中のメソッド名は、次のようにして取得できる。ただし、パフォーマンス悪いので注意。

String methodName = new Throwable().getStackTrace()[0].getMethodName();

ユーティリティメソッド化するなら、次のように書ける。

public class AppUtil {
	/**
	 * 現在メソッド名を取得する。
	 */
	public static String getMethod() {
		return new Throwable().getStackTrace()[1].getMethodName();
	}
}

ラムダ式(Java8以降)

Java8からラムダ式が導入されました。これにより、今まで関数型インタフェースなどで記述していたメソッド引数が書きやすくなりました。

次のようなメソッドがあったとします。

// 呼び出し対象メソッド
private static void runLambda(FuncInterface action) {
	action.run("Hello World");
}
// 独自の関数型インタフェース
private interface FuncInterface {
	public void run(String msg);
}

上記メソッドを呼び出すとき、Java7までは、次のように書きました。

runLambda(new FuncInterface() {
	@Override
	public void run(String msg) {
		System.out.println(msg);
	}
});

Java8からは次のように書けるようになります。

runLambda((msg) -> {
	System.out.println(msg);
});

上記では関数型インタフェースを独自に定義しましたが、Java8では、いくつかの関数型インタフェースがあらかじめ用意されるようになりました。詳細は、下記リンクを参照。

ストリームAPI(Java8以降)

Java8からストリームAPIが導入された。これにより、コレクションが操作しやすくなり、並列処理のパフォーマンス向上が期待できるらしい。 入出力ストリームとは無関係。

たとえば、今まで、次のように記述していたのが、

long count = 0;
for (String e : list) {
	if (e.length() > 4) {
		count++;
	}
}
System.out.println(count);

Java8からは、次のように書ける。

long count = list.stream().filter(w -> w.length() > 4).count();
System.out.println(count);

日時(Java1.4~7)

Java1.4~7では、主に、Dateクラス、Calendarクラスを使う。 Apache Commons LangのDateUtilsDateFormatUtilsも使えると便利。

現在/指定日時の作成

Dateクラスの現在/指定日時を作成する。

// 現在日時
Date nowDate1 = new Date();
// 文字列→Date
DateFormat dateTimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date1 = dateTimeFormat.parse("2016/5/2 15:00:00");
// 文字列→Date(Apache Commons Lang)
// ※Java5から、書式引数を可変長引数として記述できるようになった。
Date date1b = DateUtils.parseDate("2016/5/2 15:00:00", "yyyy/MM/dd HH:mm:ss");
Date date1c = DateUtils.parseDate("2016-5-2 15:00:00", "yyyy/MM/dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss");
// Calendar→Date
Date date2 = new GregorianCalendar(2016, 5 - 1, 2, 15, 0, 0).getTime();
// long→Date
Date date3 = new Date(System.currentTimeMillis());

Calendarクラスの現在/指定日時を作成する。

// 現在日時
Calendar nowCal1 = Calendar.getInstance();
// 指定日時
Calendar cal1 = new GregorianCalendar(2016, 5 - 1, 2, 15, 0, 0);
// Date→Calendar
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date1);
// Date→Calendar(Apache Commons Lang)
Calendar cal2b = DateUtils.toCalendar(date1);
// long→Calendar
Calendar cal3 = Calendar.getInstance();
cal3.setTimeInMillis(System.currentTimeMillis());

long型(ミリ秒)の現在/指定日時を作成する。

// 現在日時
long nowMsec1 = System.currentTimeMillis();
// 指定日時
long msec1 = System.currentTimeMillis() - 24 * 60 * 60 * 1000;
// Date→long
long msec2 = date1.getTime();
// Calendar→long
long msec3 = cal1.getTimeInMillis();

文字列の現在/指定日時を作成する。

// Date→文字列
DateFormat timestampFormat1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
String str1 = timestampFormat1.format(date1);
// Date→文字列(Apache Commons Lang)
String str1b = DateFormatUtils.format(date1, "yyyy/MM/dd HH:mm:ss.SSS");
// Calendar→文字列
String str2 = format.format(cal1.getTime());
// long→文字列
String str3 = format.format(new Date(msec1));

日時から日付の取り出し

// Date 日時→日付(時刻ゼロ)
Calendar tmpCal1 = Calendar.getInstance();
tmpCal1.setTime(date1);
Calendar tmpCal2 = new GregorianCalendar(tmpCal1.get(Calendar.YEAR), tmpCal1.get(Calendar.MONTH),
		tmpCal1.get(Calendar.DATE));
Date ymdDate1 = tmpCal2.getTime();

// Calendar 日時→日付(時刻ゼロ)
Calendar ymdCal1 = new GregorianCalendar(cal1.get(Calendar.YEAR), cal1.get(Calendar.MONTH),
		cal1.get(Calendar.DATE));

// 上記以外に、書式"yyyy/MM/dd"のフォーマットで文字列として取得することも可能。

日時から時刻の取り出し

// 時刻のみを取り出すことは出来ない模様。
// 必要なら、書式"HH:mm:ss"のフォーマットで文字列として取得する(?)

曜日の取得

// Dateから曜日取得
// ※ロケールによって曜日の表記が変わる。
DateFormat weekFormat1 = new SimpleDateFormat("E", Locale.JAPANESE);
DateFormat weekFormat2 = new SimpleDateFormat("EEEE", Locale.JAPANESE);
String weekStr1 = weekFormat1.format(date1);
String weekStr2 = weekFormat2.format(date1);

// Calendarから曜日取得
int weekInt1 = cal1.get(Calendar.DAY_OF_WEEK);
String[] weekNames = new String[] { "日", "月", "火", "水", "木", "金", "土" };
String weekStr3 = weekNames[weekInt1 - 1];

// Java6では、Calendar.getDisplayNameメソッドが使える。
String weekStr4 = cal1.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.JAPANESE);
String weekStr5 = cal1.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.JAPANESE);

// Dateから曜日取得(Apache Commons Lang)
// ※ロケールによって曜日の表記が変わる。
String weekStr6 = DateFormatUtils.format(date1, "E", Locale.JAPANESE);
String weekStr7 = DateFormatUtils.format(date1, "EEEE", Locale.JAPANESE);
// Calendarから曜日取得(Apache Commons Lang)
// ※ロケールによって曜日の表記が変わる。
String weekStr8 = DateFormatUtils.format(cal1, "E", Locale.JAPANESE);
String weekStr9 = DateFormatUtils.format(cal1, "EEEE", Locale.JAPANESE);

日時計算

加算/減算

// Date 1秒後、1日後
// ※Java5では、TimeUnitが使えるようになった。
Date nextSecDate = new Date(msec1 + TimeUnit.SECONDS.toMillis(1));
Date nextDayDate = new Date(msec1 + TimeUnit.DAYS.toMillis(1));

// Calendar 1秒後、1日後、1ヶ月後
Calendar nextSecCal = (Calendar) cal1.clone();
nextSecCal.add(Calendar.SECOND, 1);
Calendar nextDayCal = (Calendar) cal1.clone();
nextDayCal.add(Calendar.DATE, 1);
Calendar nextMonthCal = (Calendar) cal1.clone();
nextMonthCal.add(Calendar.MONTH, 1);

// Date 1秒後、1日後(Apache Commons Lang)
Date nextSecDate2 = DateUtils.addSeconds(date1, 1);
Date nextDayDate2 = DateUtils.addDays(date1, 1);
Date nextMonthDate2 = DateUtils.addMonths(date1, 1);

月初/月末を求める。

// Calendar 月初、月末
Calendar monthBeginning = (Calendar) cal1.clone();
monthBeginning.set(Calendar.DATE, 1);
Calendar monthEnd = (Calendar) cal1.clone();
monthEnd.set(Calendar.DATE, cal1.getActualMaximum(Calendar.DATE));

差を求める。

// Date 日時の差 ミリ秒単位、日数単位(切り捨て)
// ※日付の差がほしいときは、日時→日付のみに変換して計算する。
long dateDiffMsec = nextDayDate.getTime() - date1.getTime();
long dateDiffDays = (nextDayDate.getTime() - date1.getTime()) / TimeUnit.DAYS.toMillis(1);
// Calendar 日時の差 ミリ秒単位、日数単位(切り捨て)
// ※日付の差がほしいときは、日時→日付のみに変換して計算する。
long calDiffMsec = nextDayCal.getTimeInMillis() - cal1.getTimeInMillis();
long calDiffDays = (nextDayCal.getTimeInMillis() - cal1.getTimeInMillis()) / TimeUnit.DAYS.toMillis(1);

// Date 日付の差(Apache Commons Lang)
long dateDiffDays2 = (DateUtils.truncate(nextDayDate, Calendar.DATE).getTime()
		- DateUtils.truncate(date1, Calendar.DATE).getTime()) / TimeUnit.DAYS.toMillis(1);
// Calendar 日付の差(Apache Commons Lang)
long calDiffDays2 = (DateUtils.truncate(nextDayCal, Calendar.DATE).getTimeInMillis()
		- DateUtils.truncate(cal1, Calendar.DATE).getTimeInMillis()) / TimeUnit.DAYS.toMillis(1);

比較する。

// Dateの前後比較
boolean dateBeforeFlag = date1.before(nextDayDate);
boolean dateAfterFlag = nextDayDate.after(date1);
// Calendarの前後比較
boolean calBeforeFlag = cal1.before(nextDayCal);
boolean calAfterFlag = nextDayCal.after(cal1);

// Date 日付一致確認(Apache Commons Lang)
// ※時刻は無視して、日付のみ比較される。
boolean dateSameFlag = DateUtils.isSameDay(date1, nextSecDate);
// Calendar 日付一致確認(Apache Commons Lang)
// ※時刻は無視して、日付のみ比較される。
boolean calSameFlag = DateUtils.isSameDay(cal1, nextSecCal);

スリープ

Java5のTimeUnitを使うと、好きな時間単位でスリープ時間を書きやすい。

TimeUnit.SECONDS.sleep(1);

参考

日時(Java8)

Java8では、Java7までのDate,Calendarの代替として、次のクラスなどが導入された。

  • Instant - 日時(エポック秒)
  • LocalDateTime - タイムゾーンなし日時
  • ZonedDateTime - タイムゾーンあり日時

現在/指定日時の作成

Instantクラスの現在/指定日時を作成する。

// 現在日時
Instant nowInstant = Instant.now();
// long→Instant
Instant instant2 = Instant.ofEpochMilli(msec1);
// LocalDateTime→Instant
Instant instant3b = localDt1.toInstant(ZoneId.systemDefault().getRules().getOffset(Instant.EPOCH));
// ZonedDateTime→Instant
Instant instant4ca = zonedDt1.toInstant();
Instant instant4cb = Instant.from(zonedDt1);
// 文字列→Instant
Instant instant5 = Instant.parse("2007-12-03T10:15:30.00Z");

LocalDateTimeクラスの現在/指定日時を作成する。

// 現在日時
LocalDateTime nowLocalDt = LocalDateTime.now();
// 指定日時
LocalDateTime localDt2 = LocalDateTime.of(2016, 5, 2, 15, 0, 0);
// long→LocalDateTime
LocalDateTime localDt3 = LocalDateTime.ofInstant(Instant.ofEpochMilli(msec1), ZoneId.systemDefault());
// Instant→LocalDateTime
LocalDateTime localDt4 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault());
// ZonedDateTime→LocalDateTime
LocalDateTime localDt5a = zonedDt1.toLocalDateTime();
LocalDateTime localDt5b = LocalDateTime.from(zonedDt1);
// 文字列→LocalDateTime
LocalDateTime localDt6a = LocalDateTime.parse("2007-12-03T10:15:30.123");
LocalDateTime localDt6b = LocalDateTime.parse("2007/12/03 10:15:30.123",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS"));

ZonedDateTimeの現在/指定日時を作成する。

// 現在日時
ZonedDateTime nowZonedDt = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
// 指定日時
ZonedDateTime zonedDt2 = ZonedDateTime.of(2016, 5, 2, 15, 0, 0, 0, ZoneId.of("Asia/Tokyo"));
// long→ZonedDateTime
ZonedDateTime zonedDt3 = ZonedDateTime.ofInstant(Instant.ofEpochMilli(msec1), ZoneId.systemDefault());
// Instant→ZonedDateTime
ZonedDateTime zonedDt4a = instant1.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDt4b = ZonedDateTime.ofInstant(instant1, ZoneId.systemDefault());
// LocalDateTime→ZonedDateTime
ZonedDateTime zonedDt5a = localDt1.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDt5b = ZonedDateTime.ofLocal(localDt1, ZoneId.systemDefault(), null);
// 文字列→ZonedDateTime型
ZonedDateTime zonedDt6a = ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]");
ZonedDateTime zonedDt6b = ZonedDateTime.parse("2016/05/02 10:15:30 Asia/Tokyo",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss VV"));
ZonedDateTime zonedDt6c = ZonedDateTime.parse("2016/05/02 10:15:30 JST",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss zzz"));

文字列の現在/指定日時を作成する。

// Instant→文字列
String instantStr1 = DateTimeFormatter.ISO_INSTANT.format(instant1);
String instantStr2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS")
		.format(LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()));
// LocalDateTime→文字列
String localStr1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS").format(localDt1);
// ZonedDateTime→文字列
// "xxxxx VV" - (例)"+09:00 Asia/Tokyo"
// "xxxx zzz" - (例)"+0900 JST"
String zonedStr1a = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSxxxxx VV").format(zonedDt1);
String zonedStr1b = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSxxxx zzz").format(zonedDt1);

日時から日付/時刻の取り出し

// Instant 日時→日付
Instant ymdInstant1 = instant1.truncatedTo(ChronoUnit.DAYS);

// LocalDateTime 日時→日付、時刻
LocalDate localDate1 = localDt1.toLocalDate();
LocalTime localTime1 = localDt1.toLocalTime();

// ZonedDateTime 日時→日付、時刻
ZonedDateTime ymdZoned1 = zonedDt1.truncatedTo(ChronoUnit.DAYS);
LocalDate localDate2 = zonedDt1.toLocalDate();
LocalTime localTime2 = zonedDt1.toLocalTime();

曜日の取得

// Instant→曜日
String instantWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE)
		.format(LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()));
String instantWeek2 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()).getDayOfWeek()
		.getDisplayName(TextStyle.FULL, Locale.JAPANESE);

// LocalDateTime→曜日
// ※"E","EEEE"は、タイムゾーンによって曜日の表記が変わる。
String localWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE).format(localDt1);
String localWeek2 = localDt1.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPANESE);

// ZonedDateTime→曜日
// ※"E","EEEE"は、タイムゾーンによって曜日の表記が変わる。
String zonedWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE).format(zonedDt1);
String zonedWeek2 = zonedDt1.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPANESE);

日時計算

加算/減算

// LocalDateTime 1秒後、1日後、1ヶ月後
LocalDateTime localNextSec = localDt1.plusSeconds(1);
LocalDateTime localNextDay = localDt1.plusDays(1);
LocalDateTime localNextMonth = localDt1.plusMonths(1);
// ZonedDateTime 1秒後、1日後、1ヶ月後
ZonedDateTime zonedNextSec = zonedDt1.plusSeconds(1);
ZonedDateTime zonedNextDay = zonedDt1.plusDays(1);
ZonedDateTime zonedNextMonth = zonedDt1.plusMonths(1);

月初/月末を求める。

// LocalDateTime 月初、月末
LocalDateTime localMonthBeginning = localDt1.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime localMonthEnd = localDt1.with(TemporalAdjusters.lastDayOfMonth());
// ZonedDateTime 月初、月末
ZonedDateTime zonedMonthBeginning = zonedDt1.with(TemporalAdjusters.firstDayOfMonth());
ZonedDateTime zonedMonthEnd = zonedDt1.with(TemporalAdjusters.lastDayOfMonth());

差を求める。

// LocalDateTime 日時の差 ミリ秒単位、日数単位(切り捨て)
long localDiffMsec = ChronoUnit.MILLIS.between(localDt1, localNextDay);
long localDiffDays1 = ChronoUnit.DAYS.between(localDt1, localNextDay);
long localDiffDays2 = ChronoUnit.DAYS.between(localDt1.toLocalDate(), localNextDay.toLocalDate());
// LocalDateTime 日時の差 時分秒単位、年月日単位
Duration localDuration = Duration.between(localDt1, localNextDay);
Period localPeriod = Period.between(localDt1.toLocalDate(), localNextDay.toLocalDate());
// ZonedDateTime 日時の差 ミリ秒単位、日数単位(切り捨て)
long zonedDiffMsec = ChronoUnit.MILLIS.between(zonedDt1, zonedNextDay);
long zonedDiffDays1 = ChronoUnit.DAYS.between(zonedDt1, zonedNextDay);
long zonedDiffDays2 = ChronoUnit.DAYS.between(zonedDt1.toLocalDate(), zonedNextDay.toLocalDate());
// ZonedDateTime 日時の差 時分秒単位、年月日単位
Duration zonedDuration = Duration.between(zonedDt1, zonedNextDay);
Period zonedPeriod = Period.between(zonedDt1.toLocalDate(), zonedNextDay.toLocalDate());

比較する。

// LocalDateTime
boolean localAfterFlag = localNextDay.isAfter(localDt1);
// ZonedDateTime
boolean zonedAfterFlag = zonedNextDay.isAfter(zonedDt1);

参考

io/テキストファイル

行単位で読み書き(Java1.4)

書き込み

PrintWriter pw = null;
try {
	pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));
	pw.println("Hello World");
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (UnsupportedEncodingException e) {
	e.printStackTrace();
} finally {
	if (pw != null) {
		pw.close();
	}
}

読み込み

BufferedReader br = null;
try {
	br = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));
	String line;
	while ((line = br.readLine()) != null) {
		System.out.println(line);
	}
} catch (UnsupportedEncodingException e) {
	e.printStackTrace();
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} finally {
	if (br != null) {
		try {
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

行単位で読み書き(Java7)

書き込み Java7から、try-with-resources文が使えるようになった。それ以外は、Java6までと同様。

try (PrintWriter pw = new PrintWriter(
		Files.newBufferedWriter(Paths.get(path), Charset.forName("UTF-8"), StandardOpenOption.CREATE))) {
	pw.println("Hello World");
} catch (IOException e) {
	e.printStackTrace();
}

読み込み。 Java7から、try-with-resources文が使えるようになった。それ以外は、Java6までと同様。

try (BufferedReader br = Files.newBufferedReader(Paths.get(path), Charset.forName("UTF-8"))) {
	String line;
	while ((line = br.readLine()) != null) {
		System.out.println(line);
	}
} catch (IOException e) {
	e.printStackTrace();
}

行単位で読み込み(Java8)

読み込み。 Java8から、ストリームAPI、ラムダ式が使えるようになった。

try (Stream<String> stream = Files.lines(Paths.get(path), Charset.forName("UTF-8"))) {
	stream.forEach(System.out::println);
} catch (IOException e) {
	e.printStackTrace();
}

一括で読み書き(Java7)

書き込み。 Java7から、Files,Pathsが使えるようになった。

List<String> lines = new ArrayList<String>();
lines.add("Hello World");
try {
	Files.write(Paths.get(path), lines, Charset.forName("UTF-8"), StandardOpenOption.CREATE);
} catch (IOException e) {
	e.printStackTrace();
}

読み込み。 Java7から、Files,Pathsが使えるようになった。

try {
	List<String> lines = Files.readAllLines(Paths.get(path), Charset.forName("UTF-8"));
	System.out.println(StringUtils.join(lines, System.lineSeparator()));
} catch (IOException e) {
	e.printStackTrace();
}

一括で読み書き(Apache Commons IO)

書き込み

// リストからファイル書き込み
List<String> lines = new ArrayList<String>();
lines.add("Hello Apache Commons IO");
try {
	FileUtils.writeLines(new File(path), "UTF-8", lines, SystemUtils.LINE_SEPARATOR);
} catch (IOException e) {
	e.printStackTrace();
}

// 文字列からファイル書き込み
String text = "Hello Apache Commons IO\n" + "サンプルテキスト\n";
try {
	FileUtils.writeStringToFile(new File(path), text, "UTF-8");
} catch (IOException e) {
	e.printStackTrace();
}

読み込み

// ファイルからリストへ読み込み
try {
	List<String> lines = FileUtils.readLines(new File(path), "UTF-8");
	System.out.println(StringUtils.join(lines, SystemUtils.LINE_SEPARATOR));
} catch (IOException e) {
	e.printStackTrace();
}

// ファイルから文字列へ読み込み
try {
	String text = FileUtils.readFileToString(new File(path), "UTF-8");
	System.out.println(text);
} catch (IOException e) {
	e.printStackTrace();
}

トークン単位の読み込み(Java5)

読み込み。 Java5では、Scannerが使えるようになった。空白や改行などでトークン分割された文字列を順次読み込む。

Scanner scanner = null;
try {
	scanner = new Scanner(new File(path), "UTF-8");
	while (scanner.hasNext()) {
		String line = scanner.next();
		System.out.println(line);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} finally {
	if (scanner != null) {
		scanner.close();
	}
}

io/ファイル操作

リソースファイル

リソースファイル読み込み

InputStream is = ClassLoader.getSystemResourceAsStream(クラスパス先頭からのファイルパス);
InputStream is = getClass().getResourceAsStream(指定クラスからのファイルパス);

プロパティファイル

プロパティファイル読み込み

Properties prop = new Properties();
prop.load(new FileInputStream(new File("sample.properties")));
String value = prop.getProperty("item");

JSONファイル

JSONIC - Json/Javaオブジェクトマッパー。

* JSONIC - simple json encoder/decoder for java http://jsonic.osdn.jp/

YAMLファイル

SnakeYaml - YAMLファイルを読み書きするライブラリ。

* Google Code Archive - Long-term storage for Google Code Project Hosting. https://code.google.com/archive/p/snakeyaml/

io/ログ

ログ出力(Java標準ロガー)

Java標準APIのロガーは、1.4から使えるようになった。

// 当クラスと同じパッケージ内からプロパティファイル読み込み
try {
	LogManager.getLogManager().readConfiguration(this.getClass().getResourceAsStream("logging.properties"));
} catch (SecurityException e) {
	throw new RuntimeException(e);
} catch (IOException e) {
	throw new RuntimeException(e);
}

// ログ出力
Logger logger = Logger.getLogger(JavaLog01.class.getName());
logger.finest("FINESTメッセージです。");
logger.finer("FINERメッセージです。");
logger.fine("FINEメッセージです。");
logger.config("CONFIGメッセージです。");
logger.info("INFOメッセージです。");
logger.warning("WARNINGメッセージです。");
logger.severe("SEVEREメッセージです。");

logging.propertiesの例

############################################################
#  	Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#  	Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
#java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
#-----------------------------------------------------------
# Pleiades Custom: Enabled one line format.
#-----------------------------------------------------------
java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
org.apache.tomcat.util.digester.Digester.level = SEVERE

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
com.tryjava.level = ALL

参考

ログ出力(Apache Log4j)

ログ出力する。

// Log4j2では、Logger#getLoggerメソッドがなくなった。
Logger logger = LogManager.getLogger(Log4j01.class);

logger.trace("TRACEログです。");
logger.debug("DEBUGログです。");
logger.info("INFOログです。");
logger.warn("WARNログです。");
logger.error("ERRORログです。");
logger.fatal("FATALログです。");

// Log4j2では、パラメータの埋め込みが使えるようになった。
logger.info("Hello, {}!", "World");

Apache Log4j 1.2で使用するlog4j.properties

# Log4j 1.2 プロパティファイル

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1, FILE1

# A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n

# FILE1
log4j.appender.FILE1=org.apache.log4j.RollingFileAppender
log4j.appender.FILE1.File=./work/log4j.log
log4j.appender.FILE1.MaxFileSize=100KB
log4j.appender.FILE1.MaxBackupIndex=3
log4j.appender.FILE1.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

# Print only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN
log4j.logger.com.tryjava=ALL

Apache Log4j 2.xで使用するlog4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
	<Appenders>
		<!-- コンソール出力 -->
		<Console name="Console" target="SYSTEM_OUT">
			<!-- <PatternLayout pattern="%d{yyy/MM/dd HH:mm:ss.SSS} [%t] %-5level
				%logger{36} - %msg%n"/> <PatternLayout pattern="%d{yyy/MM/dd HH:mm:ss.SSS}
				%-5level - %msg%n" /> -->
			<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{1} - %msg%n" />
		</Console>
		<!-- ファイル出力 -->
		<RollingFile name="File" fileName="./work/log4j.log"
			filePattern="./work/log4j-%d{yyyy-MM-dd}-%i.zip">
			<PatternLayout
				pattern="%d{yyy/MM/dd HH:mm:ss.SSS} [%t] %-5level %logger - %msg%n" />
			<Policies>
				<!-- JVM開始時にログファイル切り替え -->
				<OnStartupTriggeringPolicy />
				<!-- ファイルサイズで切り替え -->
				<SizeBasedTriggeringPolicy size="20MB" />
				<!-- 日付が変わったときに切り替え -->
				<TimeBasedTriggeringPolicy />
			</Policies>
			<DefaultRolloverStrategy max="3" />
		</RollingFile>
	</Appenders>
	<Loggers>
		<Root level="INFO">
			<AppenderRef ref="Console" />
		</Root>
		<Logger name="com.tryjava" level="ALL" additivity="false">
			<AppenderRef ref="Console" />
			<AppenderRef ref="File" />
		</Logger>
	</Loggers>
</Configuration>

Apache Log4j 1.2 の参考

Apache Log4j 2.x の参考

ログAPIラッパー(Apache Commons Logging)

Apache Commons Loggingは、汎用インターフェースを提供するのみ。 実際のログ出力は、Log4jやJava標準APIなどを使用する。

Apache Commons Loggingが使用するログ実装は、次の優先順序で選択される。

  1. commons-logging.propertiesファイルがあれば、そのファイルで指定されるログ実装を使う。
  2. システムプロパティorg.apache.commons.logging.Logが定義されていれば、その定義に従う。
  3. クラスパスにLog4jが見つかれば、Log4jを使う。
  4. Java1.4以上を使用していれば、Java標準のロガーを使う。
  5. Apache Commons Loggingの簡単なログ実装を使う。

Log4jで提供しているlog4j-jclをクラスパスに通すと、Log4j2も使用できるらしい。

Log log = LogFactory.getLog(this.getClass());
log.trace("TRACEログです。");
log.debug("DEBUGログです。");
log.info("INFOログです。");
log.warn("WARNログです。");
log.error("ERRORログです。");
log.fatal("FATALログです。");

参考

net/ネットワーク

HTTPアクセス(Java標準API)

簡単なGET操作です。

HttpURLConnection con = null;
try {
	// リクエスト作成
	URL url = new URL("http://localhost:8080/tryjava-dummy-web/echo");
	con = (HttpURLConnection) url.openConnection();
	con.setRequestMethod("GET");

	// レスポンスコード取得
	int statusCode = con.getResponseCode();
	System.out.println(statusCode + " " + con.getResponseMessage());
	if (statusCode != HttpURLConnection.HTTP_OK) {
		throw new RuntimeException("エラーレスポンスを受信しました。statusCode=" + statusCode);
	}

	// レスポンスボディ取得
	System.out.println(con.getContentType());
	InputStream is = con.getInputStream();
	String encoding = getEncoding(con);
	String content = IOUtils.toString(is, encoding);
	System.out.println(content);

} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
} finally {
	if (con != null) {
		con.disconnect();
	}
}

上記コード内で使用している簡易的な文字コード判定処理です。

String getEncoding(HttpURLConnection con) {
	String encoding = null;
	Matcher matcher = Pattern.compile("charset=(.*)", Pattern.CASE_INSENSITIVE).matcher(con.getContentType());
	if (matcher.find()) {
		encoding = matcher.group(1);
	}
	System.out.println("encoding=" + encoding);
	return encoding;
}

少し複雑なGETです。

HttpURLConnection con = null;
try {
	// リクエスト作成
	URL url = new URL("http://localhost:8080/tryjava-dummy-web/echo" //
			+ "?param1=value1" //
			+ "&UrlEncode=" + URLEncoder.encode("+-/_", "UTF-8"));

	con = (HttpURLConnection) url.openConnection();
	con.setRequestMethod("GET");
	// リダイレクト許可
	con.setInstanceFollowRedirects(true);
	// キャッシュ設定
	con.setUseCaches(true);
	// タイムアウト設定(ミリ秒単位)
	// ※Java5から使用可能。
	con.setConnectTimeout(60 * 1000);
	con.setReadTimeout(60 * 1000);
	// ヘッダー設定
	con.setRequestProperty("Accept-Language", "ja");
	con.setRequestProperty("X-Header1", "value1");

	// 接続
	con.connect();

	// レスポンスコード取得
	int statusCode = con.getResponseCode();
	System.out.println(statusCode + " " + con.getResponseMessage());
	if (statusCode != HttpURLConnection.HTTP_OK) {
		throw new RuntimeException("エラーレスポンスを受信しました。statusCode=" + statusCode);
	}

	// レスポンスヘッダ取得
	con.getHeaderFields().forEach((key, values) -> {
		System.out.println(key + ": " + ToStringBuilder.reflectionToString(values, ToStringStyle.SIMPLE_STYLE));
	});

	// レスポンスボディ取得
	System.out.println(con.getContentType());
	InputStream is = con.getInputStream();
	String encoding = getEncoding(con);
	String content = IOUtils.toString(is, encoding);
	System.out.println(content);

} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
} finally {
	if (con != null) {
		con.disconnect();
	}
}

POSTリクエストです。レスポンス受信は、GETの時と同じ。

// リクエスト作成
URL url = new URL("http://localhost:8080/tryjava-dummy-web/echo");
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
// POSTパラメータ
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), "UTF-8"));
w.write("param1=value1");
w.write("&UrlEncode=" + URLEncoder.encode("+-/_", "UTF-8"));
w.write("&text=" + URLEncoder.encode("日本語", "UTF-8"));
w.flush();

プロキシを使う場合は、事前に次の処理をしておきます。

System.setProperty("proxySet", "true");
System.setProperty("proxyHost", PROXY_HOST);
System.setProperty("proxyPort", String.valueOf(PROXY_PORT));
Authenticator.setDefault(new Authenticator() {
	@Override
	protected PasswordAuthentication getPasswordAuthentication() {
		return new PasswordAuthentication(PROXY_USER, PROXY_PASSWORD.toCharArray());
	}
});

// この後、HttpURLConnection作成して、HTTP通信を行う。

参考

HTTPアクセス(Apache Commons HttpCient

Apache Commons HttpCientは、Java1.4で使用可能。 Java5以降が使えるなら、Apache HttpComponents HttpClientを使用したほうが良い。

簡単なGETです。

// クライアント作成
HttpClient client = new HttpClient();

// リクエスト作成
HttpMethod method = new GetMethod("http://localhost:8080/tryjava-dummy-web/echo");

try {
	// 接続
	int statusCode = client.executeMethod(method);
	System.out.println("statusCode=" + statusCode);
	if (statusCode != HttpStatus.SC_OK) {
		throw new RuntimeException("エラーレスポンスを受信しました。statusCode=" + statusCode);
	}

	// レスポンスボディ取得
	byte[] responseBody = method.getResponseBody();
	System.out.println(new String(responseBody, "UTF-8"));

} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
} finally {
	method.releaseConnection();
}

少し複雑なGETです。

// クライアント作成
HttpClient client = new HttpClient();

try {
	// リクエスト作成
	HttpMethod method = new GetMethod("http://localhost:8080/tryjava-dummy-web/echo");
	// クエリ―文字列は、URLエンコードされる。
	// UTF-8以外を使いたいときは、EncodingUtilを使うらしい。
	method.setQueryString(new NameValuePair[] { //
			new NameValuePair("param1", "value1"), //
			new NameValuePair("UrlEncode", "+-/_"), //
			new NameValuePair("text", "日本語"), //
	});
	// ヘッダー設定
	method.addRequestHeader("Accept-Language", "ja");
	method.addRequestHeader("X-Header1", "value1");

	try {
		// 接続
		int statusCode = client.executeMethod(method);
		System.out.println("statusCode=" + statusCode);
		if (statusCode != HttpStatus.SC_OK) {
			throw new RuntimeException("エラーレスポンスを受信しました。statusCode=" + statusCode);
		}

		// レスポンスヘッダ取得
		Header[] headers = method.getResponseHeaders();
		for (int i = 0; i < headers.length; i++) {
			System.out.print(headers[i]);
		}

		// レスポンスボディ取得
		byte[] responseBody = method.getResponseBody();
		System.out.println();
		System.out.println(new String(responseBody, "UTF-8"));

	} finally {
		method.releaseConnection();
	}
} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

POSTリクエストです。レスポンス受信などは、GETの時と同じ。

// リクエスト作成
PostMethod method = new PostMethod("http://localhost:8080/tryjava-dummy-web/echo");
// POSTパラメータ
// POSTパラメータは、URLエンコードされる。
method.getParams().setContentCharset("UTF-8");
method.setRequestBody(new NameValuePair[] { //
		new NameValuePair("param1", "value1"), //
		new NameValuePair("UrlEncode", "+-/_"), //
		new NameValuePair("text", "日本語"), //
});
// 次の書き方でも良い。
// method.addParameter("param1", "value1");
// method.addParameter("UrlEncode", "+-/_");
// method.addParameter("text", "日本語");

PUTリクエストです。レスポンス受信などは、GETの時と同じ。

// リクエスト作成
PutMethod method = new PutMethod("http://localhost:8080/tryjava-dummy-web/echo");
// パラメータ
method.getParams().setContentCharset("UTF-8");
method.setRequestEntity(new StringRequestEntity("{" //
		+ "\"param1\":\"value1\"" //
		+ "\"UrlEncode\":\"+-/_\"" //
		+ "\"text\":\"日本語\" //" //
		+ "}", null, "UTF-8"));

Basic認証のプロキシを使う場合です。

// クライアント作成
HttpClient client = new HttpClient();
// プロキシ設定
client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
client.getState().setProxyCredentials( //
		new AuthScope(PROXY_HOST, PROXY_PORT), //
		new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));

参考

HTTPアクセス(Apache HttpComponents HttpClient 4.3より前)

Apache HttpComponents HttpClientは、Java5以上で使用可能。 Apache HttpComponents HttpClient 4.3にて、インターフェース変更あり。

簡単なGETです。

try {
	HttpClient client = new DefaultHttpClient();

	// リクエスト作成
	HttpGet request = new HttpGet("http://localhost:8080/tryjava-dummy-web/echo");

	try {
		// 接続
		HttpResponse response = client.execute(request);

		// レスポンスコード取得
		StatusLine statusLine = response.getStatusLine();
		System.out.println(statusLine);
		if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
			throw new RuntimeException("エラーレスポンスを受信しました。statusLine=" + statusLine);
		}

		// レスポンスボディ取得
		HttpEntity entity = response.getEntity();
		String content = EntityUtils.toString(entity);
		System.out.println(content);
	} finally {
		request.releaseConnection();
	}

} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

少し複雑なGETです。

try {
	HttpClient client = new DefaultHttpClient();

	// リクエスト作成
	// GETパラメータは、URLエンコードされる。
	URIBuilder builder = new URIBuilder("http://localhost:8080/tryjava-dummy-web/echo")
			.addParameter("param1", "value1") //
			.addParameter("UrlEncode", "+-/_"));
	HttpGet request = new HttpGet(builder.build());
	request.addHeader("Accept-Language", "ja");
	request.addHeader("X-Header1", "value1");
	System.out.println(request.getRequestLine());

	try {
		// 接続
		HttpResponse response = client.execute(request);

		// レスポンスコード取得
		StatusLine statusLine = response.getStatusLine();
		System.out.println(statusLine);
		if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
			throw new RuntimeException("エラーレスポンスを受信しました。statusLine=" + statusLine);
		}

		// レスポンスヘッダ取得
		for (Header header : response.getAllHeaders()) {
			System.out.println(header);
		}

		// レスポンスボディ取得
		HttpEntity entity = response.getEntity();
		String content = EntityUtils.toString(entity);
		System.out.println();
		System.out.println(content);
	} finally {
		request.releaseConnection();
	}

} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

POSTリクエストです。レスポンス受信などは、GETの時と同じ。

// リクエスト作成
// POSTパラメータは、URLエンコードされる。
HttpPost request = new HttpPost("http://localhost:8080/tryjava-dummy-web/echo");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("param1", "value1"));
params.add(new BasicNameValuePair("UrlEncode", "+-/_"));
params.add(new BasicNameValuePair("text", "日本語"));
request.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

Basic認証のプロキシを使う場合です。

// クライアント作成
DefaultHttpClient client = new DefaultHttpClient();
// プロキシ設定
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
client.getCredentialsProvider().setCredentials( //
		new AuthScope(proxy), //
		new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));

参考

HTTPアクセス(Apache HttpComponents HttpCilent4.3以降)

Apache HttpComponents HttpClientは、Java5以上で使用可能。

簡単なGETです。

// Java7からtry-with-resourcesが使用可能
try (CloseableHttpClient client = HttpClients.createDefault()) {

	// リクエスト作成
	HttpGet request = new HttpGet("http://localhost:8080/tryjava-dummy-web/echo");

	// 接続
	// Java7からtry-with-resourcesが使用可能
	try (CloseableHttpResponse response = client.execute(request)) {

		// レスポンスコード取得
		StatusLine statusLine = response.getStatusLine();
		System.out.println(statusLine);
		if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
			throw new RuntimeException("エラーレスポンスを受信しました。statusLine=" + statusLine);
		}

		// レスポンスボディ取得
		HttpEntity entity = response.getEntity();
		String content = EntityUtils.toString(entity);
		System.out.println(content);
	}
} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

少し複雑なGETです。

// Java7からtry-with-resourcesが使用可能
try (CloseableHttpClient client = HttpClients.createDefault()) {

	// リクエスト作成
	// GETパラメータは、URLエンコードされる。
	URIBuilder builder = new URIBuilder("http://localhost:8080/tryjava-dummy-web/echo")
			.setCharset(Charset.forName("UTF-8")) //
			.addParameter("param1", "value1") //
			.addParameter("UrlEncode", "+-/_"));
	HttpGet request = new HttpGet(builder.build());
	request.addHeader("Accept-Language", "ja");
	request.addHeader("X-Header1", "value1");
	System.out.println(request.getRequestLine());

	// 接続
	// Java7からtry-with-resourcesが使用可能
	try (CloseableHttpResponse response = client.execute(request)) {

		// レスポンスコード取得
		StatusLine statusLine = response.getStatusLine();
		System.out.println(statusLine);
		if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
			throw new RuntimeException("エラーレスポンスを受信しました。statusLine=" + statusLine);
		}

		// レスポンスヘッダ取得
		for (Header header : response.getAllHeaders()) {
			System.out.println(header);
		}

		// レスポンスボディ取得
		HttpEntity entity = response.getEntity();
		String content = EntityUtils.toString(entity);
		System.out.println();
		System.out.println(content);
	}
} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

POSTリクエストです。レスポンス受信などは、GETの時と同じ。

// リクエスト作成
// POSTパラメータは、URLエンコードされる。
HttpPost request = new HttpPost("http://localhost:8080/tryjava-dummy-web/echo");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("param1", "value1"));
params.add(new BasicNameValuePair("UrlEncode", "+-/_"));
params.add(new BasicNameValuePair("text", "日本語"));
request.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

Basic認証のプロキシを使う場合です。

// プロキシ設定
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials( //
		new AuthScope(proxy), //
		new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));
RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
HttpClientBuilder builder = HttpClients.custom() //
		.setDefaultCredentialsProvider(provider) //
		.setDefaultRequestConfig(config);

// Java7からtry-with-resourcesが使用可能
try (CloseableHttpClient client = builder.build()) {
	// あとは省略。

参考

HTTPアクセス(Apache HttpComponents Fluent API)

Apache HttpComponents Fluent APIは、Java5以上で使用可能。

簡単なGETです。

try {
	Content content = Request.Get("http://localhost:8080/tryjava-dummy-web/echo").execute().returnContent();
	System.out.println(content.asString());
} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

簡単なPOSTです。

try {
	Content content = Request.Post("http://localhost:8080/tryjava-dummy-web/echo")
			.bodyForm(Form.form().add("username", "my-name").add("password", "my-password").build()).execute()
			.returnContent();
	System.out.println(content.asString());
} catch (Exception e) {
	throw new RuntimeException("HTTP通信に失敗しました。", e);
}

URLエンコード/デコード

Java1.0からの標準APIでURLエンコード/デコードができる。

String encoded = URLEncoder.encode("https://www.tryjava.com/path/name?key1=value1&key2=おはよう#name", "UTF-8");
System.out.println(encoded);
String decoded = URLDecoder.decode(encoded, "UTF-8");
System.out.println(decoded);

参考

util/ユーティリティ

Base64(Apache Commons)

Java7以下では、標準APIにBase64が含まれていない。Apache Commonsを使って次のように書ける。

byte[] encoded = Base64.encodeBase64("こんにちは".getBytes("UTF-8"));
System.out.println(new String(encoded));

byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(new String(decoded, "UTF-8"));

Base64(Java8)

Java8から、標準APIにBase64ライブラリが追加された。

Encoder encoder = Base64.getEncoder();
byte[] encoded = encoder.encode("こんにちは".getBytes("UTF-8"));
System.out.println(new String(encoded));

Decoder decoder = Base64.getDecoder();
byte[] decoded = decoder.decode(encoded);
System.out.println(new String(decoded, "UTF-8"));

ext/コマンドラインアプリケーション

実行時引数を操作(Apache Commons CLI)

実行時引数を解析する。

public static void main(String[] args) {
	Options options = new Options();
	options.addOption("h", "help", false, "ヘルプを表示する。");
	options.addOption("a", "aaa", false, "引数なしオプションです。");
	options.addOption("b", "bbb", true, "引数ありオプションです。");

	// パーサー生成
	// Apache Commons CLI 1.2では、BasicParserを使用していたが、
	// 1.3では、DefaultParserを使用する。
	DefaultParser parser = new DefaultParser();

	try {
		CommandLine cl = parser.parse(options, args);

		if (cl.hasOption("h")) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("command_name [options] <infile>", options);
		} else {
			System.out.println("オプションa : " + cl.hasOption("a"));
			System.out.println("オプションb : " + cl.getOptionValue("b"));
			System.out.println("必須引数 : " + cl.getArgs()[0]);
		}
	} catch (ParseException e) {
		e.printStackTrace();
	}
}

ext/JavaFx

簡単な例(JavaFx 8)

Java8で導入された。 FXMLと呼ばれる XMLとCSSを併用してデザインを記述らしい。

簡単な例

public class JavaFx01 extends Application {
	@Override
	public void start(Stage stage) throws Exception {
		Label message = new Label("Hello, JavaFX!");
		message.setFont(new Font(100));
		stage.setScene(new Scene(message));
		stage.setTitle("Hello");
		stage.show();
	}
}

次のように起動する。 ※もしかしたら、クラスパスにjfxrt.jarを入れる必要があるかもしれない。

java -cp %CLASSPATH% com.tryjava.ext.javafx.JavaFx01

Eclipseから実行するときは、mainメソッドがあったほうが良いかも。 mainメソッドは次のように書ける。

public static void main(String[] args) {
	launch(args);
}

テキストボックスやボタンを使った例

public class JavaFx02 extends Application {
	@Override
	public void start(Stage stage) throws Exception {
		String title = this.getClass().getSimpleName();
		Label titleLabel = new Label(title);
		TextField textField = new TextField();

		Label msgLabel = new Label();
		msgLabel.setText("入力結果:");

		Button updateButton = new Button("更新");
		updateButton.setOnAction((actionEvent) -> {
			msgLabel.setText("入力結果:" + textField.getText());
		});

		Button closeButton = new Button("閉じる");
		closeButton.setOnAction((actionEvent) -> {
			stage.hide();
		});

		VBox pane = new VBox();
		pane.setPadding(new Insets(20));
		pane.setSpacing(10);
		pane.getChildren().add(titleLabel);
		pane.getChildren().add(textField);
		pane.getChildren().add(msgLabel);
		pane.getChildren().add(updateButton);
		pane.getChildren().add(closeButton);

		stage.setScene(new Scene(pane));
		stage.setTitle(title);
		stage.show();
	}
}

参考

ext/XML

XMLデータ

JAXB

Java SE 6以降では、JAXB(Java Architecture for XML Binding)というOXM(オブジェクト/XMLマッパー)が使える。

オブジェクト→XML変換

// 入力オブジェクト
Person person = new Person();
person.name = "山田 太郎";
person.age = 20;

// オブジェクト→XML変換
StringWriter sw = new StringWriter();
JAXB.marshal(person, sw);
String xml = sw.toString();

XML→オブジェクト変換

// 入力XML
String input = "" //
		+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" //
		+ "<person>\n" //
		+ "    <name>山田 太郎</name>\n" //
		+ "    <age>20</age>\n" //
		+ "</person>\n" //
		;

// XML→オブジェクト変換
StringReader sr = new StringReader(input);
Person person = JAXB.unmarshal(sr, Person.class);

詳細

Webアプリケーション

Javaフレームワーク

Java以外

単体テスト

テスト技法やキーワードなど

  • ホワイトボックス/ブラックボックス/同値クラス/境界値
  • 実測値(actual value)/期待値(expected value)
  • C0(命令網羅)/C1(分岐網羅)/C2(条件網羅)

JUnit

テストケースの粒度

  • 1つのケースで複数の実測値、期待値が必要になるということは、テスト対象が大きすぎる可能性あり。

4フェーズテスト

  • ひとつのテストケースメソッド内で、次の4つの処理に分けて、テストを記述する。
  • 1.初期化、2.テストの実行、3.アサーション、4.(必要ならば)終了処理。

テスタビリティを高めるリファクタリング

  • プロダクトコードでテスト困難な箇所をメソッドに抽出する。テストコードでは、プロダクトコードを無名クラスで継承し、テスト困難なメソッドをオーバーライドする。
  • プロダクトコードでテスト困難な箇所をオブジェクトに抽出する。テストコードで、テスト用オブジェクトをDIする。

バージョン

  • JUnit3 - Java4以下でも動作。
  • JUnit4 - Java5以上。アノテーションベース。

JUnit4

アノテーション

  • @Test - テストケース
  • @Ignore - テストの実行を除外
  • @Before - 初期化
  • @After - 後処理
  • @BeforeClass - クラスごとの初期化
  • @AfterClass - クラスごとの後処理
  • @RunWith - テストランナー

アサーション

assertThat(actual, is(expected));
fail("未実装");

Matchers

  • CoreMatchers#is, nullValue, not, notNullValue, sameInstance, instanceOf
  • JUnitMatchers#hasItem, hasItems

ルール

public class RuleTest {
    @Rule
    public TestRule rule = new SomeRule();
    @ClassRule
    public static TestRule RULE = new SomeRule();
}

例外送出のテスト

@Test(expected=Exception.class)
public void testCase() {
}

タイムアウト

@Test(timeout=1000L)
public void testCase() {
}

構造化テスト

@RunWith(Enclosed.class)
public class EnclosedTest {
    public static class XXの場合 {
        @Before
        public void setUp() {
        }
    }
    public static class YYの場合 {
        @Before
        public void setUp() {
        }
    }
}

内部クラスのまとめ方

  • 共通データでまとめる。
  • 共通の状態でまとめる。
  • コンストラクタのテストを分ける。

パラメータ化リスト

@RunWith(Theories.class)
public class ParameteriedTest {
    @DataPoints
    public static int[] PARAMS = {1, 2, 3, 4};
    @Theory
    public void test(int x) {
    }
}
@RunWith(Theories.class)
public class ParameteriedTest {
    public static class Fixture {
        public int input;
        public int expected;
        public Fixture(int input, int expected) {
            this.input = input;
            this.expected = expected;
        }
    }
    @DataPoints
    public static Fixture[] fixtures = {new Fixture(1, 10), new Fixture(2, 20)};
    @Theory
    public void test(Fixture x) {
    }
}

@DataPointsはメソッドに定義することも可能

    @DataPoints
    public static Fixture[] getPrams() {
        外部リソース読み込みなど
    }

カテゴリ化テスト

@Category(DbTests.class)
public class CategoriedTest {
    @Test
    @Category(SlowTests.class)
    public void testCase() {
    }
}

ライブラリ

Apache Commons CLI

Mavenでの記述例

<dependency>
	<groupId>commons-cli</groupId>
	<artifactId>commons-cli</artifactId>
	<version>1.3.1</version>
</dependency>

Apache Commons IO

Mavenでの記述例

<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.5</version>
</dependency>

Apache Commons Lang

Mavenでの記述例(バージョン3系)

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.4</version>
</dependency>

Mavenでの記述例(バージョン2系)

<dependency>
	<groupId>commons-lang</groupId>
	<artifactId>commons-lang</artifactId>
	<version>2.6</version>
</dependency>

Apache Commons Logging

Mavenでの記述例

<dependency>
	<groupId>commons-logging</groupId>
	<artifactId>commons-logging</artifactId>
	<version>1.2</version>
</dependency>

Apache HttpComponents / Apache Commons HttpClient

Apache HttpComponents HttpClient / Apache Commons HttpClient

  • バージョン4以降のサイト http://hc.apache.org/
  • バージョン3.xのサイト http://hc.apache.org/httpclient-3.x/
  • バージョン4.3で、大幅なインファーフェース変更。
  • バージョン4.xは、Java5以上が必要。
  • バージョン3.xは、Java1.4で使用可能。

Mavenでの記述例(バージョン4系)

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.3.6</version>
</dependency>

Mavenでの記述例(バージョン3系)

<dependency>
	<groupId>commons-httpclient</groupId>
	<artifactId>commons-httpclient</artifactId>
	<version>3.1</version>
</dependency>

Apache HttpComponents Fluent

  • バージョン4.xは、Java5以上が必要。
  • Java1.4では使用不可。

Mavenでの記述例

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>fluent-hc</artifactId>
	<version>4.3.6</version>
</dependency>

Apache Log4j

  • バージョン2.4は、Java7以上が必要。
  • バージョン2.0は、Java6以上が必要。
  • バージョン1.2は、Java1.4で使用可能。

Mavenでの記述例(バージョン2系)

<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-api</artifactId>
	<version>2.5</version>
</dependency>
<dependency>
	<groupId>org.apache.logging.log4j</groupId>
	<artifactId>log4j-core</artifactId>
	<version>2.5</version>
</dependency>

Mavenでの記述例(バージョン1系)

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>

キーワード