今更人に聞けないJava5からの新機能(J2SE 5.0)

More than 3 years have passed since last update.


はじめに

Javaのバージョン番号について、ところどころで1.8のように表記されている個所が出てきます。

リリース当初のJavaは1.3、1.4のようにマイナーバージョンがアップされていましたが、1.5のタイミングで5.0とメジャーバージョンを変えていくようになりました。

Java内のフォルダー名や表記など至るところで「1.X」と表記されている個所がありますが、実際にはXのバージョンを差すので混乱しないよう気をつけてください。


J2SE 5.0


当時の社会

J2SE 5.0は2004年9月30日にリリースされました。コードネームは「Tiger」。

2004年9月、プロ野球再編問題が発生し、近鉄の球団売却、オリックスとの合併、そして楽天イーグルスが誕生しました。ライブドアが騒がれていたのもこの頃です。

この年2月にはmixiとgreeがほぼ同時にサービス開始。調べたらFacebookも2004年の2月にサービス開始していたんですね。

「ソーシャルネットワーク」元年だったのではないでしょうか。

7月にはipod miniが発売され爆発的な大ヒットになりました。それらももう10年以上前のことです。

Java1.5は多くの言語機能が追加されました。これまで0.1刻みで増やしていたバージョン名を「Java5」と呼ぶようになったのはその思いの表れでしょうか。

Java1.5のEOL(End Of Life)は2009年10月です。そのため現在バグフィックスやセキュリティアップデートが実施できません。

現在もJava1.5を使う場合、脆弱性を狙う攻撃を防ぐセキュリティ製品を導入するか、もしくは日本オラクルが提供する有償サポートを利用します。


総称型(ジェネリクス)

総称型(ジェネリクス)とは、汎用的なクラスやメソッドを特定の型に対応させる仕組みのことです。

ジェネリクスを使うと、型の情報を変数化することが出来ます。


GenericsSample1.java

public class GenericsSample1 {

//ジェネリクスを使ったクラスを定義
static class Container<T>{
//変数の型として型変数を使うことが出来る
private T value;

//引数の型として型変数を使うことが出来る
Container(T value){
this.value = value;
}

//メソッドの戻り値として型変数を使うことが出来る
T get(){
return value;
}
}

public static void main(String[] args){
Container<Integer> container1 = new Container<Integer>(100); //型変数T = Integer
System.out.println("container1 is "+container1.get()); //メソッドgetの戻り値はInteger
Container<String> container2 = new Container<String>("Generics"); //型変数T = String
System.out.println("container2 is "+container2.get()); //メソッドgetの戻り値はString
}
}


「T型ってなんだよ?!フォードかよ?!」と突っ込みたくなる人のためにこの記事を書いています。

ジェネリクスを使うことで、同じクラス、メソッドに<>で囲まれた型パラメータを指定し、任意の型を変数として扱うことが出来ます。

見て分かるように、Containerクラス内で使用されるT型は、オブジェクトを生成する際にIntegerになったり、Stringになったりします。

【ここが便利】

ジェネリクスが主に導入されているコレクションクラスを例に説明します。

僕がはじめてJavaを覚えた頃、配列から要素を取り出すときにはたしかにこのように書いていました。

ArrayList al = new ArrayList();

al.add("りんご");
al.add("みかん");
al.add("バナナ");

String str = (String) al.get(0);

getメソッドはObject型を返すため、変数に要素を格納する場合はキャストが必要でした。

        ArrayList<String> al = new ArrayList();

al.add("りんご");
al.add("みかん");
al.add("バナナ");

String str = al.get(0);

ジェネリクスを使えば、キャストが不要になります。

また、ジェネリクスを使うことで、ArrayListに格納できるオブジェクトの型を限定できることも大きなメリットです。

限定することで思わぬ型の値が格納されたままArrayListオブジェクトをプログラム内で使用して実行時エラーが発生、という事態を防ぐことができます(コンパイル時にエラーが表示されます)。

List<String> l = new ArrayList<String>();

l.add(10.1); // String型でないのでコンパイルエラー


型パラメータに境界をつける

型パラメータには単に型変数を宣言するだけでなく、型の種類を定義することも出来ます。

例えば、<T extends Collection>と型パラメータが宣言されていた場合、ここに渡す型はCollectionか、Collectionを継承したクラスでなければコンパイルエラーを出力します。

逆に<T super String>と型パラメータを宣言した場合、ここに渡す型はStringあるいはStringの親クラスのみ渡すことが出来ます。

【ここが便利】

ソースコードに制約を課す事で、バグをすばやく発見できるようになります。


ワイルドカード

「型パラメータが宣言されていても、実際の型変数を必要としない場合にワイルドカードを使うことが出来る」

とあっさりした説明が手元の本でなされていますが、自分としては『どういうシチュエーションだ?』というのが正直な感想です。

IBMのdeveloperworksでも

Javaの理論と実践: Generics のワイルドカードを使いこなす、第 1 回


Java言語におけるGenericsで最も複雑な部分の1つはワイルドカードであり・・・


Java の理論と実践: Generics のワイルドカードを使いこなす、第 2 回


Java言語でのGenericsのワイルドカードは非常にわかりにくく・・・


と大切なことなので2回書いています(笑)。

達人プログラマーを目指して:Java総称型のワイルドカードを上手に使いこなすための勘所


Java言語の総称型は本エントリで説明するように特殊なところがあり、単に利用するだけでも他の言語に比べて遥かに難しいところがあるというのも事実です。


読んでもちんぷんかんぷんです。

ワイルドカードを理解するには付け焼刃の知識では駄目で「総称型の親子関係」と「Javaの後方互換性」という背景を元に考えなければいけなさそうです。

放課後プログラミング:ワイルドカードの使い方 (ジェネリクスの使い方 3)

こちらの記事では『いつ使えばいいのか』という僕の疑問に対して


ワイルドカードが本質的に力を発揮するのはジェネリクスがサポートされる以前のコードを

ジェネリクスを使ったコードに書き換える時です。


とあり、


完全に新規のプロダクトをジェネリクスサポート後のjavaで実装する場合は

ワイルドカードが大活躍する場面はあまりありませんが、ジェネリクスサポート前の

プロダクトをジェネリクスで書き換える際には必要に応じてワイルドカードを使うことになります。」


と書かれています。

下手なことは書けないのでこれら外部の記事を参照してください。


オートボクシング

ボクシング、それは拳にグローブを着用しパンチのみを使い、相手の上半身前面と側面のみを攻撃対象とする格闘スポーツの一種、ではなくintやdoubleなどのプリミティブ型変数をラッパークラスという「箱に包む」ことを意味します。

何を今更、という話かもしれませんがJavaの変数の型についておさらいしましょう。

Javaで扱うことの出来る型は大きく分けて「プリミティブ型」「リファレンス型」の2種類です。

『プリミティブ型』は


  • boolean

  • byte

  • short

  • int

  • long

  • char

  • float

  • double

のいわゆる「基本データ型」。一方『リファレンス型』は


  • クラス型

  • インタフェース型

  • 型変数

  • 配列型

の4種類です。

リファレンス型は宣言すると全てnullで初期化されますが、プリミティブ型は型によって初期値が異なります。


  • boolean=false

  • byte=0

  • short=0

  • int=0

  • long=0l

  • char='\u0000' (null文字)

  • float=0.0f

  • double=0.0d

プリミティブ型にはそれぞれ対応するラッパークラスがあり、このラッパークラスはプリミティブ型の値で表される値を持ったオブジェクトになります。


  • boolean → Boolean

  • char → Character

  • byte → Byte

  • short → Short

  • int → Integer

  • long → Long

  • float → Float

  • double → Double

数値を文字列に変換するtoString()や文字列を数値に変換するperseInt()はラッパークラスのメソッドです。

基本データ型はオブジェクトではないため、メソッドは持ちません、単独では型の変換も出来ません。ラッパークラスにより型を変換してプログラム内で使用しています。

プリミティブ型からラッパークラスへの変換を「ボクシング変換」、ラッパークラスからプリミティブ型への変換を「アンボクシング変換」と呼びますが、Java5からはこの変換を自動で行ってくれるようになりました。オートなボクシング、つまり「オートボクシング」です。

【ここが便利】

先ほども挙げたコレクションクラスで威力を発揮します。

リストやコレクションに対して、直接プリミティブ型の値を挿入することが出来ないため、プリミティブラッパークラスに代入(ボクシング変換)後、リストに追加するという処理が必要でした。

    List<Integer> list = new ArrayList<Integer>();

list.add(new Integer(10));

Java5からは

    List<Integer> list = new ArrayList<Integer>();

list.add(10);

これでいけます。10はプリミティブ型ですが、Integerオブジェクトにオートボクシングしてくれるのです。便利ですね。


enum(列挙型)

とりえる値のパターンが決まっているものを表す時に使用します。

例えば、野球部、テニス部、サッカー部に対して処理を行う以下のようなプログラムがあったとします。


EnumExample.java

public class EnumExample {

public static void main(String[] args) {
if(args[0].equals("101") ){
System.out.println("野球");
}else if(args[0].equals("102")){
System.out.println("サッカー");
}else if(args[0].equals("103") ){
System.out.println("テニス");
}
}
}


実際にこんなプログラムを書く人はいないでしょうが、例えです。

「0と1以外の値がプログラム内で書かれていた場合はリファクタリングできないか考えろ」とはCode Completeの教えです。

初見で見た人は101、102が何を意味しているのか分かりませんから。このプログラムは以下のように書き換えられます。


EnumExample2.java

public class EnumExample2 {

public static final String BASEBALL_ID = "101";
public static final String SOCCER_ID = "102";
public static final String TENNIS_ID = "103";

public static void main(String[] args) {
if(args[0].equals(BASEBALL_ID) ){
System.out.println("野球");
}else if(args[0].equals(SOCCER_ID)){
System.out.println("サッカー");
}else if(args[0].equals(TENNIS_ID) ){
System.out.println("テニス");
}
}
}


少し改善されました。しかし本来なら「野球」「サッカー」「テニス」も定数で定義したものを使用するべきです。列挙型を使うとこうなります。


EnumExample3.java

public class EnumExample3 {

//列挙型の定義
enum Sports{
BASEBALL("101","野球"),SOCCER("102","サッカー"),TENNIS("103","テニス");

private String code;
private String name;

Sports(String code,String name){
this.code = code;
this.name = name;
}
public String getCode(){
return code;
}
public String getName(){
return name;
}
}

public static void main(String[] args) {
if(args[0].equals(Sports.BASEBALL.getCode()) ){
System.out.println(Sports.BASEBALL.getName());
}else if(args[0].equals(Sports.SOCCER.getCode())){
System.out.println(Sports.SOCCER.getName());
}else if(args[0].equals(Sports.TENNIS.getCode()) ){
System.out.println(Sports.TENNIS.getName());
}
}
}


enum(列挙型)はクラスと同じようにフィールド、コンストラクタ、メソッドを定義することができます。

名前の後に項目を列挙してオブジェクトを生成しています。

BASEBALL("101","野球"),SOCCER("102","サッカー"),TENNIS("103","テニス");

【ここが便利】

生成した列挙型オブジェクトは通常のオブジェクトと同じように使用することが出来ます。

列挙型のメリットは明白で、同じ属性のものをまとめて関連付けて定義できるためコードの可読性・保守性が改善されます。

さらに後述する「拡張For文」を使えば、列挙型オブジェクトの全ての値を走査して比較演算することもできてたいへん便利です。


拡張For文

僕の以前書いた記事Python基礎講座をに目を通されている聡明な読者の皆さんならばご存知でしょうが(笑)

Pythonでおなじみの「リスト型オブジェクトの先頭要素から最終要素までを1つずつ走査」がJava5から実装されました。


ForSample.java

import java.util.ArrayList;

public class ForSample {
public static void main(String[] args){
ArrayList<String> fruits = new ArrayList();
fruits.add("りんご");
fruits.add("みかん");
fruits.add("バナナ");

//for(変数型 1要素を格納する変数 : Iterableを実装したオブジェクト)
for(String s : fruits){
System.out.println(s);
}
}
}


拡張For文で指定することができるのは、配列もしくはIterableインタフェースを実装したクラスのオブジェクトです。 従ってこのインタフェースを実装すれば、自作クラスのオブジェクトも拡張for文で使用可能となります。

【ここが便利】

通常のforよりも記述が簡潔になるため、可読性が高まります。バグが入り込む可能性を減らすことが出来ます。


アノテーション(メタデータ)

「アノテーション」とは「あるデータに対して関連する情報(=メタデータ)を注釈として付与すること」ですがJavaの場合、クラス・メソッド・フィールドに様々な情報を付与することが出来ます。

アノテーションは単なる『注釈』ではありません。それならコメントで十分です。Javaのアノテーションはもっと便利です。

アノテーションは@の後ろにアノテーション名を定義して、クラスやメソッド、フィールド名の先頭に記述します。

例えば、

@Deprecated

class DeprecatedClass{

}

これはDepreccatedClassというクラスにDeprecatedというアノテーションを設定しています。


Deprecatedアノテーション

(deprecaed 形容詞:〔仕様などが〕廃止される可能性がある、廃止予定の、将来のサポートが保証されない、非推奨の)

つまり古くなってしまい今後扱うべきでないクラス・メソッド・フィールドに対して使います。

「そんなのコメントに"【非推奨】"と書いておけばいいじゃないか」って?アカーン!!

少人数で小さなプログラムを作成しているときはそれでも問題ありませんが、大規模なプログラム開発においては、複数の開発者全員が全体の概要を理解しながら、同じコーディングスタイルで開発する必要があります。

各自自分の好きなスタイルでコーディングをすると全体の統一感がなくなり、ある人の書いたコードが他の人にとっては何をやっているか分からない。書いた人も既に退職してしまっているし・・・あるあるです。

【ここが便利】

「コーディングスタイルについてルールを決めて、そのルールに従ったコードを記述する」という方法がありますが、プロジェクトごと別のルールだと結局効果が薄いです。

「このアノテーションを使おう」を決めれば、Javaプログラマならすぐにルールを理解でき、統一された規約で記述できます。

更に、Deprecatedアノテーションを設定したクラス、メソッド、フィールドをコード上で使っている場合、コンパイル時に警告を出すことが出来ます。

eclipse上でのアノテーション.png

また、eclipseなどのIDEはDeprecatedなクラス、メソッド、フィールドが視覚的に分かるような機能があります。

コメントにはなぜ非推奨なのか、変わりにどのメソッドを使うのか、あるいはいつまでにどう書き換えるか、などを記述して、後から修正する人にとって分かりやすいようにしておきましょう。

ところで上の画像にはDeprecated以外のアノテーションも例示しています。それが次に紹介するOverrideです。


Overrideアノテーション

その名のとおり、スーパークラスで定義されているメソッドをオーバーライドする際に使用します。

eclipseを使っている場合抽象クラスを継承したクラスを作成した場合、自動で必要なメソッドが追加されますが、その時にこのアノテーションが設定されますよね。

【ここが便利】

Overrideアノテーションを付けておくことで、オーバーライドするメソッドの引数の数を間違えていたり、戻り値の型が間違えているとコンパイラがエラーを通知してくれます。


SuppressWarningsアノテーション

コンパイラが出す警告を抑制する場合に使います。

@SuppressWarnings("deprecation")

public static void main(String[] args) {
ClassSample g = new ClassSample();
g.hoge(); // 非推奨のhogeメソッド
}

SuppressWarningsアノテーションで利用できる設定値には、以下のようなものがあります。


  • cast:不要なキャスト

  • deprecation:非推奨のメンバーを利用

  • divzero:ゼロで除算

  • unused:使われてない変数がある

【ここが便利】

下位互換性などの都合で非推奨のメソッドを意図的にして使っている場合に、いちいち警告が出ないようにできます。

SuppressWarningsアノテーションをつけると警告は出なくなりますが、「警告が出たか。SuppressWaningsをつけよう」は当然駄目です。

警告が出るということは実行時に問題が発生する可能性があります。意図しないものに関してはちゃんと警告が出ないように手でプログラムを直しましょう。


独自アノテーション

これまで紹介してきたアノテーションは「標準アノテーション」でしたが、アノテーションは独自のものを自作することも出来ます。以下のような構文で定義します。

アクセス修飾詞 @interface アノテーション名 {

アノテーションの定義
}

このままではjava.lang.annotation.Annotation型を継承するインタフェースに過ぎません。

これをクラスやメソッド、フィールドに関連付けることで(DeprecatedやOverrideのように)意味を持ちます。

例えば、クラスに関する情報として、「作成者」、「バージョン情報」、「クラスの簡単な説明」をソースコードに埋め込みたかったとします。



/**

* Author Taro

* Version 1.0

* Description テスト用のクラスです

*/

チームのルールで上のように書くよう決める、というのも1つのやり方かもしれませんが、しょせんコメントなのでフリーフォーマットです。必要な情報を書き忘れる可能性もあります。

ここでアノテーションを使用すれば、必要な情報を書き漏らした場合エラーが発生します。見てみましょう。


OriginalAnnotetionSample.java

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface Explanation {
int id(); //クラスのid
String username(); //製作者
double version() default 1.00; //対応バージョン
}

@Explanation(id=10,username="Taro")
class SampleClass1{
String id;
String name;
String age;
}

public class OriginalAnnotationSample {
public static void main(String [] args) {
SampleClass1 sc1 = new SampleClass1();
Annotation[] annotations = sc1.getClass().getAnnotations();
for(Annotation an : annotations){
System.out.println("Annotation: "+ an);
}
}
}


Explanationというアノテーションを作成しました。アノテーションを付与した場合は、必ずメンバの初期値を設定しなくてはなりません。

しかしversionメンバの後ろに「default 1.00」と書いてあることに気がつくと思います。

defaultキーワードで、アノテーションのメンバ初期値に、初期化しないメンバのデフォルトの値を定義することが出来ます。

「クラスを作成する時には常にExplanationアノテーションを付与する」というルールがあれば全員が抜けなくクラスの設定データを設定することが出来ます。

これだけではコメントに比べて大きなメリットがアノテーションにあるようには思えないかもしれません。

アノテーションは単に設定するだけではあまり意味がありません。アノテーションはコードでありながら、プログラムの動作には何も関わらない特殊なものです。

アノテーションの用法として、アノテーションの情報を取得するメソッドが用意されているのです。

クラスにつけられたアノテーションの情報を取得するClassクラスのgetDeclaredAnnotationsメソッド、

メソッドにつけられたアノテーションの情報を取得するMethodクラスのgetDeclaredAnnotationsメソッド、

フィールドにつけられたアノテーションの情報を取得するFieldクラスのgetDeclaredAnnotationsメソッドがあります。

これらはAnnotationオブジェクトの配列を返し、中には対象のクラス/メソッド/フィールドに付加されたアノテーションが格納されます。


AnnotationSample3.java

import java.lang.annotation.Annotation;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class AnnotationSample3 extends SuperClass{
public static void main(String args[]){
AnnotationSample sample = new AnnotationSample();

// クラスに付いているアノテーションの取得
Annotation[] annotations = sample.getClass().getDeclaredAnnotations();
for (Annotation annotation : annotations) {
String className = sample.getClass().getName();
System.out.println(className + "クラスについているアノテーション: "
+ annotation.annotationType().getName());
}

// メソッドに付いているアノテーションの取得
Method[] methods = sample.getClass().getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
Annotation[] methodAnnotations = method.getDeclaredAnnotations();
for (Annotation annotation : methodAnnotations) {
System.out.println(methodName + "メソッドに付いているアノテーション: " +
annotation.annotationType().getName());
}
}

// フィールドについているアノテーションの取得
Field[] fields = sample.getClass().getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
for (Annotation annotation : fieldAnnotations) {
System.out.println(fieldName + "フィールドに付いているアノテーション: " +
annotation.annotationType().getName());
}
}
}

@Deprecated
private static class AnnotationSample extends SuperClass{

int val1;
@Deprecated
String val2;

@Deprecated
public void method1(int i){
val1 = i;
}

public void method2(String s){
val2 = s;
}

@Override
public void superMethod(){
System.out.println("Annotation Sample");
}
}
}


AnnotationSample3$AnnotationSampleクラスについているアノテーション: java.lang.Deprecated

method1メソッドに付いているアノテーション: java.lang.Deprecated
val2フィールドに付いているアノテーション: java.lang.Deprecated

実行結果は上記のようになります。どうやらOverideしたメソッドはmethod.getDeclaredAnnotations()では取得できないようです。

【ここが便利】

アノテーションを使用することで、必要な情報を漏れなくソースコードに書くことを強制できます。

「メソッドを使用して実行時に情報を取得できる」というコメントには無い機能も紹介しました。

『アノテーションはコードでありながら、プログラムの動作には何も関わらない特殊なもの』という先ほどの説明とは矛盾しますが、取得できる以上は従来コメントに記していた情報をコンパイル時や実行時に取得して判定や処理に利用することが出来ます。

記法を統一できるだけでなく、プログラムの実行時でプログラムの情報を取得できるのはコメントでは出来なかった処理です。


メタアノテーション

ややこしいですが、アノテーションに付与できるアノテーションがあります。これをメタアノテーションと呼びます。代表的なメタアノテーションを3つ紹介します。

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)
@Documented
@interface Explanation {
int id(); //クラスのid
String username(); //製作者
double version() default 1.00; //対応バージョン
}


Retentionアノテーション

定義しているアノテーションの情報をどこまで保存するかを指定可能です。

* SOURCE:ソースコード上に記述されるのみでコンパイルすると情報は消えます。

* CLASS:クラスファイル内に情報を保持し、実行時には保持しません。独自アノテーションはこの設定がデフォルトです。

* RUNTIME:実行時にもアノテーションの情報が保持されるため、getDeclaredAnnotations()メソッドで取得可能です。


Targetアノテーション

定義しているアノテーションをコード上のどの箇所に付与できるか制限することが可能です。

* TYPE:クラス、インタフェース、enum定義型に付与できる

* FIELD:フィールドの宣言(enum定数を含む)

* METHOD:メソッドの宣言

* PARAMETER:メソッドのパラメータの宣言

* CONSTRUCTOR:コンストラクタの宣言

* LOCAL_VALIABLE:ローカル変数の宣言

* ANNOTATION_TYPE:アノテーション型の宣言

* PACKAGE:パッケージの宣言


Documentedアノテーション

このアノテーションを定義すると、定義しているアノテーションの情報がjavadocにも記載されます。

ここまで説明を読んで、自分の中に疑問が生まれました。この記述によれば、Retentionアノテーションは設定しない場合デフォルト、CLASSになるはずです。CLASSは『クラスファイル内に情報を保持し、実行時には保持しない』とあります。

しかし、”独自アノテーション”内で記述した「AnnotationSample3.java」内のクラスも、メソッドも、フィールドもRetentionアノテーションを設定していないのに、

AnnotationSample3$AnnotationSampleクラスについているアノテーション: java.lang.Deprecated

method1メソッドに付いているアノテーション: java.lang.Deprecated
val2フィールドに付いているアノテーション: java.lang.Deprecated

と出力されます。デフォルトならば実行時のgetDeclaredAnnotations()で値が取得できないのでは・・・?

と、Javaに詳しい友人にこの疑問をぶつけたところ、

「Deprecated アノテーション自体がRetantionPolicy.RUNTIMEになっているから」

TECHSCORE:7. アノテーション

Deprecated の定義は以下の通りです。

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {}

DeprecatedアノテーションにアノテーションRetention(RetentionPolicy.RUNTIME)

が付与されていた空、Deprecatedアノテーションの付与されているクラス、メソッド、フィールドいずれも実行時にアノテーションの情報が取得できたのですね。

先のページによれば、Override アノテーションとSuppressWarnings アノテーションはRetention(RetentionPolicy.SOURCE)となっているため、実行時にアノテーションは取得できないはず。勉強になりました。

【ここが便利】

アノテーションの機能を追加、設定、限定できます。


Concurrency Utilities

"Concurrency"とは「並列処理」の意味です。

マルチスレッドによる並列処理システムをjavaで実行する場合、特にシーケンシャルな処理で発生しないレースコンディションやデッドロックが発生しうります。

こういった問題を回避しつつ比較的容易にマルチスレッド関連機能を扱えるようにしてくれるパッケージがConcurrency UtilitiesというAPIです。

java.util.concurrentパッケージとそのサブパッケージに格納されています。

スレッドプールも提供されているためThreadクラスを直接使う必要もなくなり、並列処理のハードルも低くなったそうです。

参考:argius note:Concurrency Utilitiesを使った並列処理・マルチスレッドのおさらい

ただし、Javaにおける並列処理はどんどん機能が追加・変更されている分野になります。特にJava8で強化されました。

自分の記事でも後々紹介します。


可変長引数

可変長の引数を使用したいメソッドがある場合、これまでは配列を用いていました。

Java5からは変数の型の後ろに「...」とピリオドを3つつけることで、可変長引数を表すことが出来ます。


MultipleArgmentsSample.java

public class MultipleArgmentsSample {

public static void main(String[] args) {
printFruits(new String[]{"リンゴ","みかん","バナナ"});
printAnimals("ライオン","キリン","ゾウ","カバ");
}
//Java1.4までの可変長引数。配列を使っていました
private static void printFruits(String[] fruits){
for(int i=0;i < fruits.length;i++){
System.out.println(fruits[i]);
}
}
//Java5からの可変長引数 ついでに拡張for文を使ってみました
private static void printAnimals(String... animals){
for(String s:animals){
System.out.println(s);
}
}
}


【ここが便利】

分かりやすい記述でかけるようになりました。


static import

これまで他のパッケージのクラスやインタフェースを使用する時は、ソースコードの先頭にimport文を記述していました。

Java5では、staticなメソッドはimport文を使って呼び出すことが出来ます。


StaticMethodClassSample.java

package sample;

public class StaticMethodClassSample {
public static void method(){
System.out.println("StaticMethod");
}
}


sampleパッケージにstaticなメソッドmethod()を持つStaticMethodclassSampleクラスを作成しました。


StaticImportSample.java

import static sample.StaticMethodClassSample.method;

public class StaticImportSample {
public static void main(String[] args){
method();
}
}


import staticキーワードで、プログラム内で使用したいstaticメソッドを記述します。その後は従来のように「クラス名.メソッド名」と書くことなく、メソッド名だけで参照で起案す。これはメンバ変数でも同じです。

【ここが便利】

記述量が減りました。


Java 6

Java 6は2006年12月11日にリリースされました。コードネームは「Mustang」。

"J2SE" からJava SEに名称を変更し、バージョン番号から ".0" の部分を廃止しました。

既存機能の高速化、性能改善、強化が中心(と僕は判断しました)ですので、ここで新機能の説明はしません。

コレクションフレームワークにメソッドが追加されたみたいですが、今や普通に使用されているこれら機能のどれがJava6なのかちょっと分からなかったので・・・。

Java6のEOL(End Of Life)は2013年2月です。そのため現在バグフィックスやセキュリティアップデートが実施できません。

現在もJava6を使う場合、脆弱性を狙う攻撃を防ぐセキュリティ製品を導入するか、もしくは日本オラクルが提供する有償サポートを利用します。