出典: Medium Java は主に 2 つの点で批判されています。冗長性と、多くの場合明らかな必要性なしに生成される定型コードの量です。私はずっと Java が好きでしたが、これらの記述が間違っているとは言えません。それは本当です。Java の過度の詳細は、非常に煩わしい場合があります。しかし、私たちは理想的な世界に住んでいないことを認めなければならず、ほとんどの場合、2 つの悪のうち小さい方を選択しなければなりません。Java はその誕生以来、完璧ではありませんでした。これは誰もが知っていますが、本当の疑問は、なぜこれまでこれらの問題を解決するために何も行われなかったのかということです。変更にこれほど時間がかかった唯一の理由は、Java 言語に競争力がなく、現状のままだったからだと思います。Java が市場を支配したのは、おそらく有力な競合相手がいなかったことと、まず Sun が、次に Oracle が多大な努力を払ったことによるものと思われます。Java が提供する高レベルの型安全性と言語の優れた構造により、Java は大規模プロジェクトで非常に人気があります。さらに、独自の仮想マシン上で実行されるマルチプラットフォーム言語です。JIT コンパイラーによる自動パフォーマンス最適化と組み合わせることで、不適切に記述されたコードの影響が最小限に抑えられます。全体として、これは Java を使用する非常に説得力のある理由です。しかし、次に何が起こったのでしょうか?何が起こったかというと、Java と同じ JVM で実行できる新しい言語が市場に登場したということです。Java の最大の不便さのいくつかを解消し、場合によっては開発者に参入障壁を低くし、より快適な環境を提供する言語。先に進む前に、JVM 言語の歴史をざっと振り返ってみましょう。
改良されたオペレーター
Java の新しい演算子は、
JVM言語の歴史
まず、1 つ明確にしておきたいのは、既存の JVM 言語の一部については言及しなかったということです。これらの言語は、業界で広く使用される候補とみなされるほど十分なサポートがなかったからです。それでは、JVM 言語の歴史の概要を簡単に説明しましょう。まず最初に、JVM の世界で最も古く、最も人気のある言語である Java を取り上げます。Java は 1996 年 1 月に正式にリリースされたため、この言語は 24 年間存在しています。悪くないですよね?Java は元々、オブジェクト指向プログラミング スタイルに従った純粋な命令型言語でした。それはまた、強く型付けされた言語でもありました。Java の構文は C++ や C 言語に似ていますが、Java でのコードの作成は C や C++ よりもはるかに簡単であるため、改良版とみなされます。その一方で、彼の批判者の間で最大の議論がある - 冗長さ。2 番目の JVM 言語は Groovy でした。これは 2003 年から存在していますが、最初の標準バージョン 1.0 は 2007 年 1 月に登場しただけです。Groovy の利点は、スクリプト言語として使用できることです。Groovy は動的に型付けされる言語であるため、型チェックは実行時に行われます。これが、一部の開発者が Groovy を好まない理由の 1 つです。Groovy でコードを作成すると、コンパイル時には正しいように見えますが、実行時には何かが間違っていることに気づきます。その後、別の人気のある言語が登場しました。Scala について話します。2004年に発売されました。彼は、関数型プログラミングと宣言的アプローチという新しい作業モデルを JVM の世界にもたらしました。基本的に、Scala は不変性の概念を導入した最初の言語であり、その後 Java を強化するために使用されました。一方、Scala を批判する人たちは、文法が複雑で可読性がかなり低いため、Scala を好みません。JVM の世界から次に登場した言語は、純粋な関数型言語である Clojure でした。登場したのは2007年ですが、最近になってかなり人気が出てきました。Clojure は、シンプルさと単純な関数の使用を特徴とする LISP ベースの言語です。欠点としては、(Groovy のように) 動的に型指定されており、構文が他の JVM 言語とは完全に異なるため、学習曲線が非常に急であることが挙げられます。そして最後に、Kotlin を紹介します。Kotlin は 2016 年 2 月に初めて登場し、それ以来人気の高まりが止まりません。これは、最も有名な Java の問題を修正することを主な目的として JetBrains によって開発されました。設計上、Kotlin は Java のすべての利点を保持していますが、同時に多くの問題を解決しています。これらは最も重要な JVM 言語です。先ほども言いましたが、Jython、JRuby、Ceylon、Fantom など、あまり人気のない他の言語を見逃していました。必要に応じて、既存の JVM 言語のリスト全体を見つけることができます。ウィキペディアで。おそらく、Java が作成されてから最初の 8 ~ 10 年間はそれほど競合がいなかったことに気づいているでしょうが、それ以降状況は変わりました。では、競争は良いのか悪いのか?競争激化のメリット
Java は初期の頃からあまり変わっていません。おそらく必要がなかったからでしょう。この言語は広く使用されており、完璧には程遠いにもかかわらず、常に非常に人気があります。しかしその後、新しい機能を提供し、長い間 Java 開発者を悩ませてきた問題のいくつかを解決する、より現代的な言語である競合言語が登場しました。たとえば、Scala 言語を見てみましょう。Scala の人気は 2009 年以来高まっています。開発者は、この新しい関数型スタイルを歓迎し、柔軟性が高まり、並列コードを安全かつ簡単に作成できるようになりました。オラクルはこの新しい傾向にどのように対応しましたか? 2014 年に Java Lambda と Streams が登場しました。この時が Java が Scala 打倒に向けて最大の一歩を踏み出した時期だということには誰もが同意できると思います。今ではプログラマーなら誰でも、Scala がもはや流行ではないことを知っています。JVM の世界に競合他社が増えることのもう 1 つの利点は、JIT コンパイラーと JVM に継続的な改良が加えられていることです。現在、より多くの人々が JVM の最適化とパフォーマンスの向上に興味を持っています。つまり、競争は誰にとっても良いことなのです!Java の最新の代替言語は Kotlin 言語です。新しい言語は、ある意味、Oracle の進むべき道を示したので、その外観は Java の開発にとって非常に重要でした。Kotlin の例は、Java の利点を維持しながら、コードをより速く書くことができるよりコンパクトな言語を作成できることを示しました。Google トレンドのグラフを見ると、2016 年から 2018 年にかけて Kotlin の人気が急速に高まったことがわかります。しかし、過去2年間でその興奮は低下しました。オラクルは、Kotlin に対する業界の反応を詳しく調査しました。JDK 15 リリース ノートを見ると、新しい Java 機能の一部が Kotlin に付属していたもののコピーであることがわかります。これらは、新しい Java エントリ、新しいテキスト ブロック (三重引用符で囲まれた複数行の文字列)、および基本的にKotlin のswitch
演算子のコピーである新しい演算子です。when
私たちが話し合ったことはすべて、私が「Java の Kotlin化」と呼ぶものです。Kotlin は、より強力な競争相手となることで、Java に進むべき道を示しました。
Javaの「Kotlin化」
今後リリースされる Java 機能の一部は、可読性の点で大幅に改善され、Java 言語の最大の弱点の 1 つである冗長性に対処する予定です。発表された Java 機能の多くは、いくつかの Kotlin 機能と疑わしいほど似ていると主張する人もいるでしょう。ただし、それらのほとんどはプレリリース バージョンであることに注意してください。これは、JDK 14 または JDK 15 (リリース時に) をインストールしても、デフォルトではそれらを使用できないことを意味します。Java 機能プレビューは、リリースで導入される新機能ですが、デフォルトでは無効になっています。これらは開発者コミュニティからのフィードバックを収集するためだけに新しいバージョンに含まれているため、今後も変更される可能性があります。このため、実稼働コードでこれらを使用することはお勧めできません。コンパイル時にそれらを有効にするには、次のことを行う必要があります。javac --enable-preview --release 14
実行時にそれらを有効にしたい場合は、以下を実行する必要があります。
java --enable-preview YourClass
もちろん、IDE でプレビューを有効にすることもできますが、すべての新しいプロジェクトでデフォルトでプレビューを有効にしないように注意してください。Java の将来のバージョンでのコーディングに大きな影響を与える変更点を見てみましょう。
Javaの投稿
Java Records は、私たちの多くが長い間求めてきた機能です。あなたは、 toString、hashCode、equals に加えて、既存のフィールドごとに getterを実装する必要がある状況に陥ったことがあると思います。Kotlin にはこの問題を解決するデータ クラスがあり、Java もScala がすでに持っているレコード クラスをケース クラスの形式でリリースすることで同じことを行うつもりです。これらのクラスの主な目的は、不変データをオブジェクトに格納することです。例を挙げて、Java がどれほど改善されるかを見てみましょう。クラスを作成して比較するために記述する必要があるコードの量は次のとおりですEmployee
。
package com.theboreddev.java14;
import java.util.Objects;
public class Employee {
private final String firstName;
private final String surname;
private final int age;
private final Address address;
private final double salary;
public Employee(String firstName, String surname, int age, Address address, double salary) {
this.firstName = firstName;
this.surname = surname;
this.age = age;
this.address = address;
this.salary = salary;
}
public String getFirstName() {
return firstName;
}
public String getSurname() {
return surname;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
public double getSalary() {
return salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(firstName, employee.firstName) &&
Objects.equals(surname, employee.surname) &&
Objects.equals(address, employee.address);
}
@Override
public int hashCode() {
return Objects.hash(firstName, surname, age, address, salary);
}
@Override
public String toString() {
return "Employee{" +
"firstName='" + firstName + '\'' +
", surname='" + surname + '\'' +
", age=" + age +
", address=" + address +
", salary=" + salary +
'}';
}
}
そしてそれに含まれるオブジェクトもAddress
:
import java.util.Objects;
public class Address {
private final String firstLine;
private final String secondLine;
private final String postCode;
public Address(String firstLine, String secondLine, String postCode) {
this.firstLine = firstLine;
this.secondLine = secondLine;
this.postCode = postCode;
}
public String getFirstLine() {
return firstLine;
}
public String getSecondLine() {
return secondLine;
}
public String getPostCode() {
return postCode;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return Objects.equals(firstLine, address.firstLine) &&
Objects.equals(secondLine, address.secondLine) &&
Objects.equals(postCode, address.postCode);
}
@Override
public int hashCode() {
return Objects.hash(firstLine, secondLine, postCode);
}
@Override
public String toString() {
return "Address{" +
"firstLine='" + firstLine + '\'' +
", secondLine='" + secondLine + '\'' +
", postCode='" + postCode + '\'' +
'}';
}
}
これほど単純なものにはコードが多すぎるのではないでしょうか? 新しい Java エントリでこれがどのように見えるかを見てみましょう。
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
そして、Address クラスを忘れないでください。
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
これは、以前に非常に多くのコードを使用して書いたものと同じです。同意: これは素晴らしいですね。そして、節約できるコードの量と、記述の容易さです。ここで、 new 演算子との違いを見てみましょうswitch
。
改良されたオペレーターswitch
Java の新しい演算子は、switch
いくつかのバグやコードの重複など、古い問題のいくつかを解決します。新しいオペレーターを使用すると、switch
この問題は解決されます。DayOfTheWeek
これを例で説明するために、 Java で 列挙型を作成します。
public enum DayOfTheWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
その後、switch
週のどの位置がその日に対応するかを教えてくれます。まず、現在 Java 11 を使用してこれを行う方法を見てみましょう。
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;
int position = 0;
switch (dayOfTheWeek) {
case MONDAY:
position = 1;
break;
case TUESDAY:
position = 2;
break;
case WEDNESDAY:
position = 3;
break;
case THURSDAY:
position = 4;
break;
case FRIDAY:
position = 5;
break;
case SATURDAY:
position = 6;
break;
case SUNDAY:
position = 7;
break;
}
System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
現在のステートメントでは、switch
変数を使用する必要があり、曜日のいずれかを逃しても、コードは問題なくコンパイルされます。これは演算子の問題の 1 つですswitch
。演算子はエラーが発生しやすいためです。では、Java 14 ではどのように改善されるのでしょうか? 見てみましょう:
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;
int position = switch (dayOfTheWeek) {
case MONDAY -> 1;
case TUESDAY -> 2;
case WEDNESDAY -> 3;
case THURSDAY -> 4;
case FRIDAY -> 5;
case SATURDAY -> 6;
case SUNDAY -> 7;
};
System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
ご覧のとおり、新しい演算子はswitch
ステートメントとしてだけでなく、式としても使用できます。結果はより簡潔で表現力豊かになります。これだけでも、多くの人がそれらを使用するよう説得できますが、主な改善点の 1 つは、 ですべてのケースをカバーしない限りステートメントがコンパイルswitch
されないことですswitch
。たとえば、次のようなエラーが表示されます。
Error:(9, 24) java: the switch expression does not cover all possible input values
今後、演算子で大文字と小文字を区別することはできなくなりますswitch
。これは、ドキュメントwhen
で説明されている Kotlin の演算子に非常に似ています。新しいテキスト ブロックも見てみましょう。
テキストブロック
Java でJSON BLOB を変数に割り当てるのがいかに難しいかについて不平を言ったことはありますか? Java には複数行のシーケンスがあり、三重引用符で囲んで記述することができます。この機能が正式にリリースされると、複数行にわたる長いシーケンスの記述がより簡単になります。2 つのモードの違いを見てみましょう。変数でフォーマットされた JSON を使用したい場合、それは悪い結果になります。final String text = "{\"widget\": {\n" +
" \"debug\": \"on\",\n" +
" \"window\": {\n" +
" \"title\": \"Sample Konfabulator Widget\",\n" +
" \"name\": \"main_window\",\n" +
" \"width\": 500,\n" +
" \"height\": 500\n" +
" },\n" +
" \"image\": { \n" +
" \"src\": \"Images/Sun.png\",\n" +
" \"name\": \"sun1\",\n" +
" \"hOffset\": 250,\n" +
" \"vOffset\": 250,\n" +
" \"alignment\": \"center\"\n" +
" },\n" +
" \"text\": {\n" +
" \"data\": \"Click Here\",\n" +
" \"size\": 36,\n" +
" \"style\": \"bold\",\n" +
" \"name\": \"text1\",\n" +
" \"hOffset\": 250,\n" +
" \"vOffset\": 100,\n" +
" \"alignment\": \"center\",\n" +
" \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
" }\n" +
"}} ";
一方、新しいテキスト ブロックがリリースされると、すべてがはるかにシンプルになります。
final String multiLineText = """
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {\s
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}
""";
こちらの方が断然見栄えが良くなります。型定義でわかるように、これらはすべて Kotlin ですでにサポートされています。Java が競合他社の 1 つである Kotlin から、Java 自体の問題に対する多くの解決策を「継承」していることがわかりました。Oracle が Kotlin の台頭に対抗するのに間に合ったのか、あるいは遅すぎたのかはわかりません。個人的には、たとえこれらの変更が競合他社によって何らかの形で開始され、多少の遅れが生じる可能性があるとしても、Java は正しい一歩を踏み出していると信じています。
GO TO FULL VERSION