お疲れさまです、みやもとです。
唐突ですが、ちょっとJavaの学び直しをしようと思います。
書けなくはない、わかったとは言い難い
私はもともとCOBOLから始まりJavaにスキルチェンジした身の上です。
業務系システムの開発をするには困らない程度にJavaのコードを書くことはできますが、現場で使っているバージョンはえてして古いところで止まりがち。
私が経験したところは一番新しくてもJava 8。
あくまで動作環境として8になっているということで、もともとJava 6から移行したと思われるコードにはおそらくJava 8から追加された機能が含まれていません。
そんな状態でJavaの勉強会とか行くとどうなるか。
「ラムダ式…?」
「レコードって何?」
「varってJavaScriptでは?」
浦島太郎もいいとこです。
仕事する分には支障ないからいいや、と開き直れなくもないのですが、勉強会のたびに浦島するのも考えもの。
なので個人的にめぼしいところだけでも勉強しておこうと思った次第です。
おそらくJavaに詳しい方には退屈な内容かと思いますが、私の復習がJava勉強中のどなたかのお役に立てば幸いです。
困った時の生成AI
しかし、いざ勉強しようにも公式ドキュメントをバージョンごとに読み合わせて差分を確認して…とかやれるほど根気強くもなければマメでもありません。
ここは生成AIに頼ってみましょう。
生成AI使って未知の言語のハンズオン作ろうとして失敗したばっかりですが、Javaならまだ知ってる分「ここおかしくね?」というところにも気付けるはずです。たぶん。
ということで、こんなプロンプトをGeminiに投げてみました。
以下のリンクはJavaの6と21の言語仕様です。
Java 6:https://docs.oracle.com/javase/specs/jls/se6/html/j3TOC.html
Java 21:https://docs.oracle.com/javase/specs/jls/se21/html/index.html
以下のステップで初学者向けの学習資料を作ってください。
1.両者に共通する部分をJavaの概要としてまとめる
2.両者の差分のうち、機能的に重要なものをピックアップして21までの変更仕様としてまとめる
3.両者の差分が判りやすいサンプルコードを作成する
リンク先はJavaの言語仕様です。
これで生成してもらった結果がこんな感じ。
概要部分はなかなかしっかり書かれているのではないでしょうか。
では肝心な差分について。

…6から21と指定したのですが、なんか「Java 5」って見えますね。
とりあえず5の部分は飛ばして、7以降の差分としてピックアップされたところをさらっていこうと思います。
Java 7の変更点
ここからJava 7の変更点としてGeminiがピックアップしてくれた内容です。
try-with-resources
リソース (ファイル、ネットワーク接続など) の自動クローズを保証してくれるようになりました。
Geminiに頼んで書いてもらったサンプルコードは以下です。
まずはJava 6の場合。
// Java 6 (リソースのクローズを明示的に行う必要がある)
import java.io.*;
public class Java6FileHandling {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("input.txt"));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
次がJava 7の場合…と言いたいのですが、「6と21の差分」と指定したからかサンプルコードもその2バージョンになりました。
Java 21のサンプルコードが以下になります。
// Java 21 (try-with-resourcesで自動的にリソースがクローズされる)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Java21FileHandling {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
短い!
try文にリソースを指定することで「このリソースに関してtry-catchして終わったらリソースをクローズする」という指定になるわけですね。
便利ー。
ダイヤモンド演算子
ジェネリクスの型推論を簡略化するための機能です。
そしてここで初めて自分がJava 6より上のバージョンで追加された機能にも触れていたことに気付きました。
業務で出てきたっけ、出てきたはず。
ArrayListのインスタンス作成時に<>内の型を省略する書き方です。
List型の変数を定義する時はListに何を格納するかを明示しますが、インスタンス作成時には省略して良いということですね。
// Java 6 (ジェネリクスの型を明示的に指定)
import java.util.ArrayList;
import java.util.List;
public class Java6DiamondOperator {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Java");
list.add("Kotlin");
list.add("Scala");
for (String str : list) {
System.out.println(str);
}
}
}
// Java 21 (ダイヤモンド演算子で型推論)
import java.util.ArrayList;
import java.util.List;
public class Java21DiamondOperator {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Kotlin");
list.add("Scala");
for (String str : list) {
System.out.println(str);
}
}
}
switch文でString使用可能
自分がJava 6より上のバージョンで追加された機能にも触れていたことに気付いた2つ目の機能です。
そういやswitch文でString使えなかったわ!
// Java 6 (switch文でStringが使えないためEnumを使う)
public class Java6SwitchString {
enum LANGUAGE {
Java, Python, Kotlin
}
public static void main(String[] args) {
String language = "Java";
LANGUAGE lang = LANGUAGE.valueOf(language);
switch (lang) {
case Java:
System.out.println("Best Programming Language");
break;
case Python:
System.out.println("Interpreted Language");
break;
case Kotlin:
System.out.println("Modern Programming Language");
break;
default:
System.out.println("Unknown Language");
}
}
}
// Java 21 (switch文でStringが使える)
public class Java21SwitchString {
public static void main(String[] args) {
String language = "Java";
switch (language) {
case "Java":
System.out.println("Best Programming Language");
break;
case "Python":
System.out.println("Interpreted Language");
break;
case "Kotlin":
System.out.println("Modern Programming Language");
break;
default:
System.out.println("Unknown Language");
}
}
}
でも実際のところ、現場でString使うSwitch文h見かけなかったかもしれません。
個人的に勉強する時にSwitch文でString判定してたから記憶が混乱している…。
複数の例外キャッチ
Java 7から複数の例外を1つのcatchブロックで処理できるようになっていたそうです。
知らんかった…。
// Java 6 (複数の例外を別々のcatchブロックで処理)
public class Java6MultipleException {
public static void main(String[] args) {
try {
int[] arr = new int[5];
arr[5] = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Arithmetic Exception");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array Index Out Of Bounds Exception");
}
}
}
// Java 21 (複数の例外を1つのcatchブロックで処理)
public class Java21MultipleException {
public static void main(String[] args) {
try {
int[] arr = new int[5];
arr[5] = 10 / 0;
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("Exception: " + e);
}
}
}
これは明確に業務で見たことない!
というか、先述の通り普通に知りませんでした…。不勉強を反省するところ。
どんな例外が発生したのかわかりやすいようなるべく例外オブジェクトを分けて処理を書くようにと教えられたのですが、複数例外でもメッセージ表示ぐらいならまとめても良さそうですね。
一旦まとめ
ようやくJava 7の変更点ピックアップを終えることができました。
残りのGeminiセレクト差分ピックアップは8,10,15,16,21。
あと2回ぐらいに分けて書いていきたいと思います。