Yöntemlerin statik olarak içe aktarılması için iyi bir kullanım durumu nedir?


137

Sadece yöntemin statik içe aktarımı iyi bir fikir değildi bir inceleme yorum var. Statik içe aktarma, çoğunlukla statik yöntemlere sahip olan bir DA sınıfından bir yöntemdeydi. Yani iş mantığının ortasında görünüşte şu anki sınıfa ait gibi görünen bir etkinlik vardı:

import static some.package.DA.*;
class BusinessObject {
  void someMethod() {
    ....
    save(this);
  }
} 

Gözden geçiren kod değiştirmek ve istedim ama ben onunla aynı tür yapmak istekli değildi. Statik olarak içe aktarılmamasının bir nedeni, yöntemin nerede tanımlandığı, şu anki sınıfta olmadığı ve herhangi bir üst sınıfta olmadığı için kafa karıştırıcı olmasıydı, bu yüzden tanımını tanımlamak için çok fazla zaman vardı (web tabanlı inceleme sisteminin tıklanabilir olmaması IDE gibi bağlantılar :-) Bunun gerçekten önemli olduğunu düşünmüyorum, statik ithalat hala oldukça yeni ve yakında hepimiz onları bulmak için alışacağız.

Ancak, kabul ettiğim diğer neden, niteliksiz bir yöntem çağrısının mevcut nesneye ait gibi görünmesi ve bağlamları atlamamasıdır. Ama gerçekten ait olsaydı, bu süper sınıfı genişletmek mantıklı olurdu.

Yani, ne zaman gelmez statik ithalat yöntemlerine mantıklı? Ne zaman yaptın? Niteliksiz çağrıların görünüşünü beğendin mi / beğendin mi?

DÜZENLEME: Kimse onları mevcut sınıfın yöntemleri olarak karıştırmayacaksa, popüler görüş statik-içe aktarma yöntemleri gibi görünüyor. Örneğin, java.lang.Math ve java.awt.Color'dan yöntemler. Ama abs ve getAlpha belirsiz değilse readEmployee'ın neden olduğunu anlamıyorum. Birçok programlama seçeneğinde olduğu gibi, bunun da kişisel bir tercih olduğunu düşünüyorum.

Yanıtınız için teşekkürler arkadaşlar, soruyu kapatıyorum.


2
İşte statik ithalatın çok iyi kullanımı: ibm.com/developerworks/library/j-ft18
intrepidis

1
@ mr5 sözdizimi, import staticözellikstatic import
Sefil Değişken

Yanıtlar:


150

Bu, özelliği yayınladıklarında Sun'ın rehberinden (orijinal vurgu):

Peki statik içe aktarmayı ne zaman kullanmalısınız? Çok tutumlu! Bunu yalnızca sabitlerin yerel kopyalarını bildirme veya mirasın (Sabit Arayüz Antipattern'i) kötüye kullanma isteğinde bulunduğunuzda kullanın. ... Statik içe aktarma özelliğini aşırı kullanırsanız, programınızı okunamaz ve sürdürülemez hale getirerek ad alanını içe aktardığınız tüm statik üyelerle kirletebilir. Kodunuzun okuyucuları (siz de dahil, yazdıktan birkaç ay sonra), statik bir üyenin hangi sınıftan geldiğini bilmeyecektir. Tüm statik üyelerin bir sınıftan içe aktarılması, okunabilirlik açısından özellikle zararlı olabilir; yalnızca bir veya iki üyeye ihtiyacınız varsa, ayrı ayrı içe aktarın.

( https://docs.oracle.com/javase/8/docs/technotes/guides/language/static-import.html )

Özellikle belirtmek istediğim iki bölüm var:

  • Statik içe aktarma işlemlerini yalnızca "kötüye kullanım mirasına" maruz kaldığınızda kullanın . Bu durumda, BusinessObject'e sahip olmak ister misiniz extend some.package.DA? Öyleyse, statik içe aktarma bunu ele almanın daha temiz bir yolu olabilir. Asla genişletmeyi hayal etmezseniz some.package.DA, bu muhtemelen statik ithalatın zayıf bir kullanımıdır. Yazarken sadece birkaç karakteri kaydetmek için kullanmayın.
  • Tek tek üyeleri içe aktarın. Say import static some.package.DA.saveyerine DA.*. Bu, içe aktarılan bu yöntemin nereden geldiğini bulmayı çok daha kolay hale getirecektir.

Şahsen, bu dil özelliğini çok nadiren kullandım ve neredeyse her zaman sadece sabitlerle veya numaralarla, asla yöntemlerle kullanmadım. Benim için takas, neredeyse hiç buna değmez.


9
Kabul. Statik ithalat veeery zaman zaman aslında kodu takip etmek önemli ölçüde kolaylaştırdık kullandım.
Neil Coffey

65

Statik ithalatı için başka makul kullanım gibi JUnit yöntemlerden daha önceki sürümlerinde JUnit 4. ile assertEqualsve faildeney sınıfı genişletilmiş beri devralınan junit.framework.TestCase.

// old way
import junit.framework.TestCase;

public class MyTestClass extends TestCase {
    public void myMethodTest() {
        assertEquals("foo", "bar");
    }
}

JUnit 4'te, test sınıflarının artık genişletilmesine gerek yoktur TestCaseve bunun yerine ek açıklamaları kullanabilir. Daha sonra onay yöntemlerini statik olarak aşağıdakilerden alabilirsiniz org.junit.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 bu şekilde kullanarak belgeleri .


4
Kabul ediyorum. Test senaryolarını basitleştirmek, niyetin yanlış anlaşılma olasılığının düşük olduğu bir yerdir.
Bill Michell

6
Bunu projemizde yaptık ve aslında assert () kullanan ve bunun yanlış Assert paketini statik olarak içe aktarmasından geldiğini düşünen insanlarla ilgili sorunlar yaşadık. Bu sorunu bulduktan sonra, kod tabanımızın hızlı bir şekilde taranması, testlerimizde bunun yaklaşık 30 örneğini buldu, testler yürütüldüğünde DEBUG bayrağı ayarlanmadığından, test çerçevesi yürütüldüğünde 30 iddianın çalıştırılmadığı anlamına geliyor.
Chris Williams

27

Etkili Java, Second Edition , Madde 19'un sonunda, bir yardımcı program sınıfının sabitlerini kullanarak kendinizi ağır bulursanız, statik içe aktarımları kullanabileceğinizi not eder . Bu ilkenin hem sabitlerin hem de yöntemlerin statik ithalatı için geçerli olacağını düşünüyorum.

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();
    }
}

Bunun avantajları ve dezavantajları vardır. Yöntemin nerede tanımlandığı hakkında bazı acil bilgileri kaybetme pahasına kodu biraz daha okunabilir hale getirir. Ancak, iyi bir IDE tanımlamaya gitmenize izin verecektir, bu yüzden bu bir sorun değildir.

Bunu yine de dikkatli bir şekilde kullanmalısınız ve yalnızca içe aktarılan dosyadan bir çok şey kullandığınızı fark ederseniz.

Düzenleme: Bu soruya atıfta bulunduğu gibi yöntemlere daha spesifik olacak şekilde güncellendi. İlke, nelerin içe aktarıldığına bakılmaksızın uygulanır (sabitler veya yöntemler).


1
Benim sorum alanları değil, statik alma yöntemleri hakkında .
Sefil Değişken

7
Belki UtilityClassWithFrequentlyUsedMethodskısaltılmalıdır.
Steve Kuo


@ Rob-Hruska Sık sık kullanmayı planlıyorsam, statik bir içe aktarma yöntemini veya alanını yeni bir yöntemde veya alanda sarmam mümkün mü? Bu statik olarak içe aktarmama izin verir mi? gibi: double myPI = Math.PI;ve sonra myPIbunun yerine referans vermeye devam edebilirim Math.PI.
Abdul

@Abdul - Evet, yapabilirsin.
Rob Hruska

14

Okunabilirlik açısından sorunlu olabileceğini ve az miktarda kullanılması gerektiğini kabul ediyorum. Ancak ortak bir statik yöntem kullanırken okunabilirliği artırabilirler. Örneğin, bir JUnit test sınıfında, gibi yöntemler assertEqualsnereden geldikleri açıktır. Benzer yöntemler java.lang.Math.


5
Ve Math.round (d) 'ye karşı (d)' yi görmek ne kadar kötü?
Steve Kuo

5
@SteveKuo - matematikçilerin formülleri işlerken tek harfli değişken adları kullandığı aynı nedenden dolayı: daha uzun adların genel ifadenin okunabilirliğine müdahale ettiği zamanlar vardır. Birden fazla trigonometrik fonksiyon içeren bir formül düşünün. Kolayca kavradı matematik formülü: sin x cos y + cos x sin y. Java'da: olur Math.sin(x) * Math.cos(y) + Math.cos(x) * Math.sin(y). Okumak korkunç.
19:19

@ToolmakerSteve, bu yüzden usingC ++ yönergesini çok özledim : yerel olabilirler .
Franklin Yu

11

Statik içe aktarma Arraysve gibi utils sınıflarını kullanırken gereksiz sınıf adlarını kaldırmak için gerçekten yararlı olduğunu düşünüyorum Assertions.

Neden olduğundan emin değilim ama Ross referans aldığı belgede bundan bahseden son cümleyi atladı .

Uygun şekilde kullanıldığında, statik içe aktarma, sınıf adlarının tekrarlama plakasını kaldırarak programınızı daha okunabilir hale getirebilir.

Temel olarak bu blogdan kopyalandı: https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

Yani mesela:

Testlerdeki iddialar

Hepimizin aynı fikirde olduğunu düşündüğüm en açık durum bu

Assertions.assertThat(1).isEqualTo(2);

// Use static import instead
assertThat(1).isEqualTo(2);

Sınıfları ve sıralamaları kullanır

Sınıf adı, kodun okunmasını kolaylaştıran utils sınıflarını kullanırken birçok durumda kaldırılabilir

List<Integer> numbers = Arrays.asList(1, 2, 3);

// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);

java.time paketinin kullanılması gereken birkaç durumu vardır

// 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));

Ne zaman kullanılmayacağına örnek

// Ok this is an Optional
Optional.of("hello world");

// I have no idea what this is 
of("hello world");

10

Renk için çok kullanıyorum.

static import java.awt.Color.*;

Renklerin başka bir şeyle karıştırılması pek olası değildir.


1
Bu eski JUnit / Hamcrest / TestNG olandan farklı gördüğüm en iyi kullanım durumlarından biridir.
kevinarpe

3

Java ile OpenGL kullanırken "bir yardımcı sınıftan sabitlerin yoğun kullanımı" kategorisine giren bir kullanım örneği olan statik içe aktarma kullanılmasını öneriyorum

Bunu bir düşün

import static android.opengl.GLES20.*;

orijinal C kodunu taşımanıza ve okunabilir bir şey yazmanıza olanak tanır:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);

bu yaygın çirkinlik yerine:

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);

2

Statik içe aktarma, Java'nın daha önce hiç kullanmadığınız ve az önce bahsettiğiniz sorunlardan dolayı kullanmak istemediğim tek "yeni" özelliktir.


Teşekkürler Bombe. Sadece bir grup statik final içeren genişletmek ve arayüz kurmak zorunda olduklarını daha iyi anladıklarına inanıyorum.
Sefil Değişken

2

Matematik ağır kod C / C ++ java için taşıma sırasında 'import statik java.lang.Math. *' Kullanın. Matematik yöntemleri 1'den 1'e eşlenir ve sınıf adı kalifikasyonu olmadan taşınan kodu ayırmayı kolaylaştırır.


2

Utility sınıflarını kullanırken bunu çok uygun buldum.

Örneğin, kullanmak yerine: if(CollectionUtils.isNotEmpty(col))

Bunun yerine şunları yapabilirim:

import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))

Kodumda bu yardımcı programı birden çok kez kullandığımda hangi IMO kod okunabilirliğini artırır.


2

Birim testleri hakkında konuşmak: Çoğu insan, alaycı çerçevelerin sağladığı when()veya gibi çeşitli statik yöntemler için statik içe aktarma kullanırverify() .

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Ve elbette, birini kullanırken ve sadece kullanmanız gerektiğini iddia ettiğinizde assertThat(), gerekli hamcrest eşleştiricilerini statik olarak içe aktarmak için kullanışlı olur:

import static org.hamcrest.Matchers.*;

1

Özellikle çok sayıda içe aktarılan yöntemin çağrıldığı ve yerel ve içe aktarılan yöntemler arasındaki ayrımın açık olduğu durumlarda, söz konusu tehlikeyi azaltmak için faydalıdırlar.

Bir örnek: java.lang.Math'e birden çok başvuru içeren kod

Başka: Sınıf adını her referansa eklemenin, inşa edilen yapıyı gizleyeceği bir XML oluşturucu sınıfı


1

Statik ithalat gettext tarzı NLS için temiz olduğunu düşünüyorum.

import static mypackage.TranslatorUtil._;

//...
System.out.println(_("Hello world."));

Bu, dizeyi ayıklanması gereken bir dize olarak işaretler ve dizeyi çevirisiyle değiştirmek için kolay ve temiz bir yol sağlar.


1

IMO statik içe aktarma oldukça güzel bir özelliktir. Statik içe aktarmaya aşırı bağımlı olmanın, kodu okunamaz hale getirdiği ve hangi sınıfın statik bir yönteme veya özelliğe ait olduğunu anlamasını zorlaştırdığı kesinlikle doğrudur. Ancak, tecrübelerime göre, özellikle Utilbazı statik yöntemler ve öznitelikler sağlayan sınıflar tasarlanırken kullanılabilir bir özellik haline gelir . Statik ithalat sağlarken ortaya çıkan belirsizlik, kod standartları belirlenerek atlatılabilir. Bir şirketteki tecrübelerime göre bu yaklaşım kabul edilebilir ve kodu daha temiz ve kolay anlaşılır hale getirir. Tercihen _karakteri ön statik yöntemlere ve statik özelliklere eklerim (bir şekilde C'den benimsenir). Görünüşe göre bu yaklaşım Java'nın adlandırma standartlarını ihlal ediyor, ancak kodlamaya açıklık sağlıyor. Örneğin, bir AngleUtils sınıfımız varsa:

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){

    }
}

Bu durumda statik içe aktarma netlik sağlar ve kod yapısı benim için daha zarif görünüyor:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

        float initialAngle = _ZERO;
        float angle1, angle2;
        _addAngle(angle1, angle2);
    }
}

Birisi statik bir içe aktarmadan hangi yöntemin veya niteliğin geldiğini söyleyebilir ve ait olduğu sınıfın bilgilerini gizler. Bir modülün ayrılmaz bir parçası olan ve bu durumda hangi sınıfın belirli statik işlevsellik sağladığını bilmek önemlidir.


Yeniden adlandırma önerisi için teşekkürler. BTW, öndeki bir alt çizgi geleneksel olarak bazı ortamlarda özel yöntemleri / alanları adlandırmak için kullanılır. Böyle bir tadil edilmiş kuralı, düşünüyorum H_bir ithalat için Helper, veya sahip yardımcı sınıfı C_için Common, veya U_için Utility. Alternatif olarak, bu yaygın olarak kullanılan sınıflar için bir veya iki karakter sınıfı adı kullanmayı düşündüm, ancak bazen yerel adlarla çakışabileceğinden endişeliydim - büyük harf yöntem adlarıyla bazı eski kodlara sahip olabilirler.
ToolmakerSteve

-1

Bunları şu durumlarda kullanmanız gerekir:

  • switchenum değerleri olan bir ifade kullanmak istersiniz
  • kodunuzun anlaşılmasını zorlaştırmak istiyorsunuz

9
Bu doğru değil. (1) Enum sabitlerini statik olarak içe aktarmadan mükemmel bir şekilde kullanabilirsiniz. (2) JUnit Assert sınıfı yöntemlerinin statik ithalatı zil olarak açıktır. "assertTrue (...)", "Assert.assertTrue (...)" kadar okunabilir, belki de moreso.
Alan Krueger

5
500 satırlık bir sınıfta 5 statik içe aktarma varsa, yöntemlerin nereden geldiğini söylemek çok zordur.
davetron5000

4
Kodunuzun anlaşılmasını zorlaştırmak istediğinizde +1)
Sefil Değişken

-5

Onları elimden geldiğince kullanıyorum. Unutursam hatırlatmak için IntelliJ kurulumum var. Bence tam nitelikli bir paket adından çok daha temiz görünüyor.


13
Düzenli ithalat yapmayı düşünüyorsunuz. Statik içe aktarmalar, bir sınıfın üyelerini sınıf adıyla nitelendirmeden göndermenize olanak tanır, örn. Static import java.lang.system.out; out.println ( "fan"); // System.out.println ("foo") yerine;
sk.

Şimdi bu statik ithalatın çok iyi bir açıklaması ... çok kötü Bir yorumu +
1'leyemiyorum
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.