質問
メソッドの静的インポートが良いアイデアではなかったというレビュー コメントを受け取りました。静的インポートは、ほとんどが静的メソッドを持つ DA クラスからのメソッドでした。したがって、ビジネス ロジックの途中で、明らかに現在のクラスに属していると思われる da アクティビティがありました。
import static some.package.DA.*;
class BusinessObject {
void someMethod() {
....
save(this);
}
}
査読者は私がコードを変更することに熱心ではなかったので、私は変更しませんでしたが、私も彼の意見にはある程度同意します。静的インポートを行わなかった理由の 1 つは、メソッドがどこで定義されているかわかりにくく、現在のクラスにもスーパークラスにもなかったので、その定義を特定するのに時間がかかりすぎたことです (Web ベースのレビュー システムにはクリック可能な機能がありません)。 IDE のようなリンク:-) これはあまり重要ではないと思いますが、静的インポートはまだ非常に新しいものであり、すぐに私たち全員がそれらを見つけることに慣れるでしょう。
しかし、もう 1 つの理由は、私も同意しますが、修飾されていないメソッド呼び出しは現在のオブジェクトに属しているように見えるため、コンテキストをジャンプすべきではないということです。しかし、それが本当に属するのであれば、そのスーパークラスを拡張するのが理にかなっています。
そうするとき する 静的インポートメソッドを使用するのは理にかなっていますか?いつやったの?不適格コールの見た目は気に入りましたか?
編集:一般的な意見は、誰もがメソッドを現在のクラスのメソッドと混同しない限り、メソッドを静的にインポートするというもののようです。たとえば、java.lang.Math および java.awt.Color のメソッドです。しかし、abs と getAlpha が曖昧ではないのであれば、readEmployee が曖昧である理由が分かりません。多くのプログラミングの選択と同様に、これも個人的な好みの問題だと思います。
皆様、ご返答ありがとうございました。質問を終了させていただきます。
解決
これは、機能をリリースしたときのサンのガイドによるものです(元々強調):
では、いつ静的インポートを使用すべきですか? 非常に控えめに!定数のローカルコピーを宣言したり、継承を悪用したい(Constant Interface Antipattern)場合にのみ使用してください。 ...静的インポート機能を使いすぎると、プログラムが読み取り不能になり、保守できなくなり、インポートするすべての静的メンバーで名前空間が汚染されます。あなたのコードの読者(あなたを含めて、あなたが書いた数ヶ月後)は、静的メンバーがどのクラスに由来するかを知りません。クラスからすべての静的メンバーをインポートすることは、読みやすさに特に有害です。必要なメンバーが1人または2人の場合は、個別にインポートします。
( https://docs.oracle .com / javase / 8 / docs / technotes / guides / language / static-import.html )
具体的に説明したい部分が2つあります:
- 「継承を悪用」したいときに静的インポートを使用するのみ。この場合、BusinessObjectを
extend some.package.DA
にしたいと思われましたか?もしそうなら、静的なインポートはこれを処理するよりクリーンな方法かもしれません。some.package.DA
を拡張することを夢見ていない場合、これはおそらく静的インポートの不適切な使用です。入力時に数文字を保存するためだけに使用しないでください。 - 個々のメンバーをインポートします。
DA。*
ではなくimport static some.package.DA.save
と言います。これにより、このインポートされたメソッドがどこから来たのかを見つけるのがずっと簡単になります。
個人的に、私はこの言語機能をめったに非常に使用しておらず、ほとんどの場合は定数または列挙型でのみ使用し、メソッドでは使用しません。私にとっては、トレードオフはほとんど価値がありません。
他のヒント
静的インポートのもう1つの妥当な使用法はJUnit 4です。JUnitの以前のバージョンでは、テストクラスが junitを拡張して以来、
。 assertEquals
や fail
などのメソッドが継承されました。 framework.TestCase
// old way
import junit.framework.TestCase;
public class MyTestClass extends TestCase {
public void myMethodTest() {
assertEquals("foo", "bar");
}
}
JUnit 4では、テストクラスは TestCase
を拡張する必要がなくなり、代わりにアノテーションを使用できます。その後、 org.junit.Assert
からassertメソッドを静的にインポートできます:
// new way
import static org.junit.Assert.assertEquals;
public class MyTestClass {
@Test public void myMethodTest() {
assertEquals("foo", "bar");
// instead of
Assert.assertEquals("foo", "bar");
}
}
JUnit ドキュメントこの方法で使用します。
有効なJava第2版、の最後>項目19 は、ユーティリティクラスの定数を使用して重いを見つけた場合、静的インポートを使用できることに注意します。この原則は、定数とメソッドの両方の静的インポートに適用されると思います。
import static com.example.UtilityClassWithFrequentlyUsedMethods.myMethod;
public class MyClass {
public void doSomething() {
int foo= UtilityClassWithFrequentlyUsedMethods.myMethod();
// can be written less verbosely as
int bar = myMethod();
}
}
これには長所と短所があります。メソッドがどこで定義されているかに関する即時情報を失うことを犠牲にして、コードを少し読みやすくします。ただし、優れたIDEを使用すると定義に移動できるため、これはそれほど大きな問題ではありません。
インポートしたファイルの内容を何度も何度も使用していることがわかった場合にのみ、これを控えめに使用する必要があります。
編集:この質問が参照しているものであるため、メソッドにより具体的になるように更新されました。原則は、インポート対象(定数またはメソッド)に関係なく適用されます。
読みやすさの観点から問題がある可能性があり、控えめに使用する必要があることに同意します。しかし、一般的な静的メソッドを使用すると、実際に読みやすさが向上します。たとえば、JUnitテストクラスでは、 assertEquals
などのメソッドはどこから来たのかが明らかです。同様に、 java.lang.Math
のメソッドの場合
色のために多く使用しています。
static import java.awt.Color.*;
色が他のものと混同されることはほとんどありません。
静的インポートは、 Arrays
や Assertions
などのutilsクラスを使用するときに、冗長なクラス名を削除するのに非常に役立つと思います。
理由はわかりませんが、ロスは彼が参照しているドキュメント。
適切に使用すると、静的インポートにより、クラス名の繰り返しの定型句が削除され、プログラムが読みやすくなります。
基本的にこのブログからコピー: https:/ /medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f
したがって、たとえば:
テストでのアサーション
これは最も明白なケースであり、全員が同意していると思います
Assertions.assertThat(1).isEqualTo(2);
// Use static import instead
assertThat(1).isEqualTo(2);
Utilsクラスと列挙
utilsクラスを使用するとコードが読みやすくなるため、多くの場合、クラス名を削除できます
List<Integer> numbers = Arrays.asList(1, 2, 3);
// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);
java.timeパッケージには、使用すべきいくつかのケースがあります
// Get next Friday from now, quite annoying to read
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
// More concise and easier to read
LocalDate.now().with(next(FRIDAY));
使用しない場合の例
// Ok this is an Optional
Optional.of("hello world");
// I have no idea what this is
of("hello world");
静的インポートのみが&#8220;新規&#8221;あなたが今言及した問題のために、私は一度も使用したことがなく、決して使用するつもりもないJavaの機能。
C / C ++からjavaに数学の重いコードを移植する場合、「import static java.lang.Math。*」を使用します。数学メソッドは1を1にマッピングし、クラス名の修飾なしで移植されたコードを簡単に比較します。
OpenGLをJavaで使用する場合は、静的インポートの使用をお勧めします。これは、&quot;ユーティリティクラスからの定数の頻繁な使用&quot; カテゴリ
検討する
import static android.opengl.GLES20.*;
元のCコードを移植し、次のような読みやすいものを記述できます。
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);
広く一般的なwideさの代わりに:
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(samplerUniform, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vtxBuffer);
GLES20.glVertexAttribPointer(vtxAttrib, 3, GLES20.GL_FLOAT, false, 0, 0);
これらは、特に呼び出されるインポートされたメソッドが多数あり、ローカルメソッドとインポートされたメソッドの区別が明確な場合に、冗長性を減らすのに役立ちます。
1つの例:java.lang.Mathへの複数の参照を含むコード
別: XMLビルダークラスここですべての参照にクラス名を追加すると、構築中の構造が非表示になります
静的インポートは、gettextスタイルのNLSに適していると思います。
import static mypackage.TranslatorUtil._;
//...
System.out.println(_("Hello world."));
これは、文字列を抽出する必要がある文字列としてマークし、文字列を翻訳に置き換える簡単でクリーンな方法を提供します。
IMO 静的インポートは非常に優れた機能です。確かに、静的インポートに大きく依存すると、コードが読みにくくなり、静的メソッドまたは属性がどのクラスに属しているかを理解するのが難しくなります。ただし、私の経験では、特に設計時に便利な機能になります。 Util
いくつかの静的メソッドと属性を提供するクラス。静的インポートを提供するときに必ず生じるあいまいさは、コード標準を確立することで回避できます。企業内での私の経験では、このアプローチは受け入れられ、コードがクリーンで理解しやすくなります。できれば、 _
先頭の文字 静的メソッドと静的属性 (どういうわけかCから採用). 。明らかに、このアプローチは Java の命名標準に違反していますが、コードが明確になります。たとえば、AngleUtils クラスがあるとします。
public class AngleUtils {
public static final float _ZERO = 0.0f;
public static final float _PI = 3.14f;
public static float _angleDiff(float angle1, float angle2){
}
public static float _addAngle(float target, float dest){
}
}
この場合、静的インポートにより明確になり、コード構造がよりエレガントに見えます。
import static AngleUtils.*;
public class TestClass{
public void testAngles(){
float initialAngle = _ZERO;
float angle1, angle2;
_addAngle(angle1, angle2);
}
}
どのメソッドまたは属性が静的インポートからのものであるかをすぐに知ることができ、それが属するクラスの情報は隠蔽されます。モジュールの不可欠な部分であり、静的メソッドと非静的メソッドを提供するクラスに静的インポートを使用することはお勧めしません。このような場合、どのクラスが特定の静的機能を提供するかを知ることが重要だからです。
単体テストについて:ほとんどの人は、 when()
や verify()<などの mocking フレームワークが提供するさまざまな静的メソッドに静的インポートを使用します/ code>。
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
そしてもちろん、唯一のアサートを使用する場合は、 `assertThat()を使用する必要があります。次のように、必要なハムクレストマッチャーを静的にインポートすると便利です。
import static org.hamcrest.Matchers.*;
ユーティリティクラスを使用する場合、これは非常に便利であることがわかりました。
たとえば、使用する代わりに: if(CollectionUtils.isNotEmpty(col))
代わりにできます:
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))
このユーティリティをコードで複数回使用すると、コードが読みやすくなります。
次の場合に使用する必要があります。
- 列挙値で
switch
ステートメントを使用したい - コードを理解しにくくしたい
できる限り、それらを使用します。忘れた場合に通知するIntelliJのセットアップがあります。完全修飾パッケージ名よりもずっときれいに見えると思います。