1つのロンボク島の背景
次のように関係者は説明しました:
Project Lombok makes java a spicier language by adding 'handlers' that know how to build and compile simple, boilerplate-free, not-quite-java code.
大雑把にJavaはシンプルかつ高速になることができますいくつかの「プロセス」を追加することにより、ロンボクを意味します。
2ロンボク使用
ロンボクとすることができるJavaコードを簡素化するために注釈の簡単な形態は、開発者の開発効率を高めます。このような開発として、多くの場合、JavaBeansを書く対応する追加する時間を取る必要がありする必要がゲッター/セッターを、そしておそらく書くためにコンストラクタを、等しく、他の方法、およびプロパティのゲッター/セッターメソッドが多数発生し、長い時間のために、維持する必要がある、これらの非常に長いように見えた多くの技術的な内容ずに、一度プロパティを変更し、対応するメソッドの過ちを変更することを忘れする傾向があります。
注釈は、ロンボク方法、コンパイル時に自動的に生成されたコンストラクタプロパティ、ゲッター/セッター缶等しく、ハッシュコード 、のtoStringの方法。ソースコード内の魔法のgetterメソッドとsetterメソッドがないことを表示されますが、コンパイルしたバイトコードファイル内のgetterメソッドとsetterメソッドがあります。これは、手動でコードをより簡潔に見えるように、トラブルコードを再構築する必要がなくなります。
ロンボクは、公式サイトですることができます、瓶のパッケージを参照して使用されている(https://projectlombok.org/download)ダウンロードジャーパッケージも依存関係Mavenを追加するために使用することができます。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
次に、我々は注釈でロンボクの特定の使用を解析します。
2.1 @Data
クラス、セッター/ゲッターに@data注釈、等しく、canEqual、ハッシュコード、toStringメソッドが自動的にそのような最終的な属性として、すべての特性は、発電のためのない属性セッターメソッドのクラスを生成します。
次のように公式の例は以下のとおりです。
import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;
@Data public class DataExample {
private final String name;
@Setter(AccessLevel.PACKAGE) private int age;
private double score;
private String[] tags;
@ToString(includeFieldNames=true)
@Data(staticConstructor="of")
public static class Exercise<T> {
private final String name;
private final T value;
}
}
次のようにロンボクを使用せずに、達成されています。
import java.util.Arrays;
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
public DataExample(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public void setScore(double score) {
this.score = score;
}
public double getScore() {
return this.score;
}
public String[] getTags() {
return this.tags;
}
public void setTags(String[] tags) {
this.tags = tags;
}
@Override public String toString() {
return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";
}
protected boolean canEqual(Object other) {
return other instanceof DataExample;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof DataExample)) return false;
DataExample other = (DataExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (this.getAge() != other.getAge()) return false;
if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.getScore());
result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
result = (result*PRIME) + this.getAge();
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
return result;
}
public static class Exercise<T> {
private final String name;
private final T value;
private Exercise(String name, T value) {
this.name = name;
this.value = value;
}
public static <T> Exercise<T> of(String name, T value) {
return new Exercise<T>(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
@Override public String toString() {
return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}
protected boolean canEqual(Object other) {
return other instanceof Exercise;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Exercise)) return false;
Exercise<?> other = (Exercise<?>) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
return result;
}
}
}
2.2ゲッター/セッター@ @
あなたは罰金が十分(のRequiredArgsConstructor @ @Data収集する@ ToStringメソッド、@ EqualsAndHashCode、@ゲッター/ @セッター、すべての機能があるため)ではありません@Dataはあまりにも残酷な、あなたは@ゲッター/ @セッター注釈、財産上でこのアノテーションを使用することができると思う場合は、することができます自動的に、例えば、属性に対応するゲッター/セッターメソッドを生成します。
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class GetterSetterExample {
@Getter @Setter private int age = 10;
@Setter(AccessLevel.PROTECTED) private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
}
あなたはロンボクを使用しない場合:
public class GetterSetterExample {
private int age = 10;
private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
protected void setName(String name) {
this.name = name;
}
}
2.3 @NonNull
プロパティまたはコンストラクタで使用される注釈は、ロンボク島は非空である文はパラメータを検証するために使用することができる生成し、NULLポインタを防ぐのを助けることができます。
例としては、次のとおりです:
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(@NonNull Person person) {
super("Hello");
this.name = person.getName();
}
}
ロンボクを使用しないでください。
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(@NonNull Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person");
}
this.name = person.getName();
}
}
2.4 @Cleanup
ノートは大幅にコードを簡素化し、自動的にclose()メソッドを呼び出すために私たちを助けることができます。
例としては、次のとおりです:
import lombok.Cleanup;
import java.io.*;
public class CleanupExample {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}
ロンボクを使用せずに、以下が必要です。
import java.io.*;
public class CleanupExample {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
}
2.5 @EqualsAndHashCode
デフォルトでは、使用するすべての非静的(非静的)と非過渡(非過渡的)属性が生成され、hasCodeに等しくされ、また、いくつかのプロパティを除外するために注釈を除外することができます。
例としては、次のとおりです:
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
@EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
2.6 @ToString
@ToString注釈クラスを使用して、生成ロンボクは、toString()メソッド、デフォルトでは、出力クラス名は、すべての属性は(属性が続く順序を定義)、カンマで割っますです。
includeFieldNames
trueに設定されたパラメータには、のtoString()プロパティの出力をクリアすることができます。これは少し複雑で、コードを見てより明確にいくつかになります。
ロンボク島での使用例:
import lombok.ToString;
@ToString(exclude="id")
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.getName();
}
@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
ロンボクのサンプルでは、次を使用していません。
import java.util.Arrays;
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.getName();
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public String toString() {
return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
}
}
@Override public String toString() {
return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";
}
}
2.7 @NoArgsConstructor、@RequiredArgsConstructorと@AllArgsConstructor
引数のないコンストラクタ、いくつかのパラメータが設定され、全引数のコンストラクタ。ロンボクは、より多くの引数のコンストラクタのオーバーロードを達成していません。
ロンボクのサンプルコードは次のとおりです。
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
@NoArgsConstructor
public static class NoArgsExample {
@NonNull private String field;
}
}
ロンボクのサンプルでは、次を使用していません。
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
private ConstructorExample(T description) {
if (description == null) throw new NullPointerException("description");
this.description = description;
}
public static <T> ConstructorExample<T> of(T description) {
return new ConstructorExample<T>(description);
}
@java.beans.ConstructorProperties({"x", "y", "description"})
protected ConstructorExample(int x, int y, T description) {
if (description == null) throw new NullPointerException("description");
this.x = x;
this.y = y;
this.description = description;
}
public static class NoArgsExample {
@NonNull private String field;
public NoArgsExample() {
}
}
}
3つのロンボク分析作品
ただ、この目的のために任意のコードを記述する必要はもはや、適切な注釈を追加し、ロンボク島の過程における使用を見出すません。最後に自動生成されたコードは、それを生成する方法ですか?
コアは、解像度にコメントする場所です。JDK5ノートの導入だけでなく、2つの分析方法を提供します。
- パースランタイム
あなたが反射によって注釈を得ることができるように、注釈は、@Retentionランタイムランタイムを設定する必要があります解析することができます。java.langで、反射パッケージは、インタフェースAnnotatedElementのを提供するインターフェースは、情報の注意を得るために、いくつかの方法を定義するクラス、コンストラクタ、フィールド、メソッド、パッケージなどのインターフェースを実装し、反射が非常に馴染みの友人となり反映すべきですこの分析法に精通。
- コンパイル時の解析
コンパイル時に、それぞれ、簡単な説明の下に解決するには2つのメカニズムがあります。
1)注釈処理ツール
生成しがちJDK5、JDK7が期限切れとしてマークされているので、完全にJDK6開始から削除されましたJDK8での使用は推奨されていない、あなたは、主に二つの理由です交換するプラグイン可能な注釈処理のAPI、aptでそれを置き換えることができます。
- 非標準的なパッケージの下com.sun.mirrorでAPI
- 、javacのに追加の実行の必要性を統合されていません
2)プラグイン可能な注釈処理API
JSR 269 JDK6からは、aptの代替として、追加され、それは二つの問題ががちである私たちは、コンパイラにいくつかの機能強化を行うことができるように、プログラムの実行中のjavacは、javacのを実行し、APIの実装を呼び出します解決します次のようにプロセスは次のとおりです。
ロンボク島で、本質的に「の実現であるJSR 269 API」のプログラム。次のようにエフェクト処理を持っているのjavacを使用するプロセスです。
- javacのソースコード解析は、抽象構文ツリー(AST)を生成
- 動作中ロンボク島の「JSR 269 API」プログラムを達成するために呼び出します
- このとき、第1の処理ステップでASTロンボクための各ツリーノードはここ構文ツリー(AST)に対応するクラス@Data注釈を検索するには、得、次いで構文ツリー(AST)を変更、増加するゲッターとセッターメソッドを定義
- 修正抽象構文木(AST)を使用して、javacは、新しいクラスのノード(ブロック)を追加する、つまり、バイトコードファイルを生成
ロンボクは、対応する注釈は注釈@Getter実現などHandleXXX、HandleGetter.handle()は、達成するためにソースコードを読んでいます。など、この使用してライブラリ、達成するための他の方法がありますGoogleの自動、ダガーようにとは。
4.ロンボクの長所と短所
利点:
- 注釈は、特定の開発の効率を向上させる他の方法をTOSTRING、等しい、ハッシュコードを自動的に生成コンストラクタ、ゲッター/セッターを形成することができます
- 適切な方法に注意を払うても過言ではない、コードが簡単になりましょう
- 変更プロパティを行うだけでなく、これらの特性の維持は、ゲッター/セッターメソッドを生成簡素化するとき
短所:
- これは、複数のオーバーロードされたコンストラクタのパラメータをサポートしていません。
- 手動でトラブルgetter / setterメソッドを作成する必要がなくなりますが、非常にソースコードを読むの快適さを減らし、ソースコードの可読性と整合性を低減しながら、
- IDEのプラグインのインストールを使用する必要があります
5.まとめ
ロンボクは、多くの利点がありますが、一種ロンボクIDEプラグに、より似ていますが、プロジェクトが対応するのjarパッケージに依存する必要があります。コメントでそれを使用するためには、コンパイル済みのロンボクに依存するJARパッケージので、なぜプラグインに似ていますか?使用中に、EclipseやIntelliJのIDEAのプラグインをインストールする必要がありますので、AST(抽象構文木)コンパイラを操作することにより、つまり、それはJavaの文法上の変化に変更され、バイトコード生成を変更します。スプリング依存性注入とは異なり、またはORMのMyBatisの実行時の特性であるが、コンパイル時の特性として。私は個人的になるための最も不快な場所はプラグインに依存している感じ!ロンボク島はいくつかのトラブルを解消するので、人工的に生成されたコードが、IDEは、getter / setterメソッドを生成し、支援するためのショートカットがあり、それはまた、非常に便利です。
神は、平和へのロンボク島の公表された多数のビューがあった知っています:
这是一种低级趣味的插件,不建议使用。JAVA发展到今天,各种插件层出不穷,如何甄别各种插件的优劣?能从架构上优化你的设计的,能提高应用程序性能的 ,
实现高度封装可扩展的..., 像lombok这种,像这种插件,已经不仅仅是插件了,改变了你如何编写源码,事实上,少去了代码你写上去又如何?
如果JAVA家族到处充斥这样的东西,那只不过是一坨披着金属颜色的屎,迟早会被其它的语言取代。
ワードプロセッサがなく、荒い荒いない、このようなプロジェクトは非常に類似したプラグインロンボク島にある想像し、個人的に私は本当に非常にソースコードを読むの快適さを軽減感じます。
非常に時々ゲッター/セッタープラスビジネスコードを少し与えることによって、いくつかのビジネスコードプロパティのゲッター/セッターで書くが、複数年のプロジェクトで実際の戦闘ですることは推奨されませんが、コードが大幅に特定のビジネスシナリオを簡素化することができます。いわゆるトレードオフは、おそらく、この時間は非常に便利を取得し、特定の規範を放棄します。
私は哲学、任意のプログラミング言語やプラグインは、別の強力なツールもキビのように、一人であり、プラスライフルはまだ同じ理由の航空機の大砲を獲得した場合でも、ようやく道具であることを非常に確信しています。特定のビジネス・シナリオと背の高い上の技術のブラインドを追求せずにプロジェクトの実際の状況と組み合わせることで、フィット感は非常に重要です。
ロンボクは、その長所と短所を熟知し、それは敬遠独自の長所と短所があり、実際の戦闘での柔軟な使用は王です。