Apa kasus penggunaan yang baik untuk impor statis metode?

139

Baru saja mendapat komentar ulasan bahwa impor statis saya dari metode ini bukanlah ide yang bagus. Impor statis adalah metode dari kelas DA, yang sebagian besar memiliki metode statis. Jadi di tengah logika bisnis saya memiliki aktivitas yang tampaknya termasuk dalam kelas saat ini:

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

Pengulas tidak tertarik bahwa saya mengubah kode dan saya tidak tetapi saya setuju dengan dia. Salah satu alasan yang diberikan untuk tidak mengimpor statis adalah membingungkan di mana metode itu didefinisikan, itu tidak ada di kelas saat ini dan tidak di superclass apa pun sehingga terlalu lama untuk mengidentifikasi definisinya (sistem ulasan berbasis web tidak memiliki yang dapat diklik tautan seperti IDE :-) Menurut saya ini tidak terlalu penting, impor-statis masih cukup baru dan kita semua akan segera terbiasa untuk menemukannya.

Tetapi alasan lain, yang saya setujui, adalah bahwa pemanggilan metode yang tidak memenuhi syarat tampaknya milik objek saat ini dan tidak boleh melompati konteks. Tetapi jika itu benar-benar cocok, masuk akal untuk memperluas kelas super itu.

Jadi, ketika tidak masuk akal untuk metode impor statis? Kapan kamu sudah melakukannya? Apakah / apakah Anda menyukai tampilan panggilan yang tidak memenuhi syarat?

EDIT: Pendapat populer tampaknya metode impor-statis jika tidak ada yang akan membingungkan mereka sebagai metode kelas saat ini. Misalnya metode dari java.lang.Math dan java.awt.Color. Tetapi jika abs dan getAlpha tidak ambigu, saya tidak mengerti mengapa readEmployee adalah. Seperti dalam banyak pilihan pemrograman, saya pikir ini juga merupakan hal preferensi pribadi.

Terima kasih atas tanggapan Anda, saya menutup pertanyaan.

Variabel yang Menyedihkan
sumber
2
Berikut adalah penggunaan yang sangat baik dari impor statis: ibm.com/developerworks/library/j-ft18
intrepidis
1
@ mr5 sintaksnya adalah import static, fiturnya adalahstatic import
Variabel Miserable

Jawaban:

156

Ini dari panduan Sun ketika mereka merilis fitur tersebut (penekanan pada aslinya):

Jadi, kapan sebaiknya Anda menggunakan impor statis? Sangat hemat! Hanya gunakan jika Anda tergoda untuk mendeklarasikan salinan lokal konstanta, atau menyalahgunakan pewarisan (Constant Interface Antipattern). ... Jika Anda terlalu sering menggunakan fitur impor statis, ini dapat membuat program Anda tidak dapat dibaca dan tidak dapat dikelola, mencemari namespace-nya dengan semua anggota statis yang Anda impor. Pembaca kode Anda (termasuk Anda, beberapa bulan setelah Anda menulisnya) tidak akan tahu dari kelas mana anggota statis berasal. Mengimpor semua anggota statis dari kelas bisa sangat berbahaya bagi keterbacaan; jika Anda hanya membutuhkan satu atau dua anggota, impor satu per satu.

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

Ada dua bagian yang ingin saya sebutkan secara khusus:

  • Gunakan impor statis hanya jika Anda tergoda untuk "menyalahgunakan warisan". Dalam kasus ini, apakah Anda tergoda untuk memiliki BusinessObject extend some.package.DA? Jika demikian, impor statis mungkin merupakan cara yang lebih bersih untuk menangani hal ini. Jika Anda tidak pernah bermimpi untuk memperpanjang some.package.DA, maka ini mungkin penggunaan yang buruk dari impor statis. Jangan gunakan hanya untuk menyimpan beberapa karakter saat mengetik.
  • Impor anggota individu. Ucapkan import static some.package.DA.savesebagai ganti DA.*. Itu akan membuatnya lebih mudah untuk menemukan dari mana metode impor ini berasal.

Secara pribadi, saya sangat jarang menggunakan fitur bahasa ini , dan hampir selalu hanya dengan konstanta atau enum, tidak pernah dengan metode. Pengorbanannya, bagi saya, hampir tidak pernah sepadan.

Ross
sumber
9
Sepakat. Saya kadang-kadang menggunakan impor statis veeery di mana mereka benar-benar membuat kode lebih mudah diikuti.
Neil Coffey
Saya suka menggunakannya dengan Kolektor dan aliran. Saya merasa aStream.collect(toSet())lebih mudah dibaca daripada aStream.collect(Collectors.toSet()). Apakah ini dianggap sebagai penggunaan yang tepat?
Jepret
65

Penggunaan wajar lainnya untuk impor statis adalah dengan JUnit 4. Dalam versi sebelumnya, metode JUnit seperti assertEqualsdan faildiwariskan sejak kelas pengujian diperpanjang junit.framework.TestCase.

// old way
import junit.framework.TestCase;

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

Di JUnit 4, kelas pengujian tidak perlu lagi diperluas TestCasedan sebagai gantinya dapat menggunakan anotasi. Anda kemudian dapat mengimpor metode assert secara statis dari 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 dokumen menggunakan cara ini.

Rob Hruska
sumber
4
Saya setuju. Menyederhanakan kasus uji adalah satu tempat di mana maksudnya tidak mungkin disalahpahami.
Bill Michell
6
Kami telah mengalami ini di proyek kami dan sebenarnya memiliki masalah dengan orang-orang yang menggunakan assert () dan salah mengira bahwa itu berasal dari impor statis paket Assert mereka. Setelah kami menemukan masalah ini, pemindaian cepat basis kode kami menemukan sekitar 30 contoh ini dalam pengujian kami yang berarti bahwa 30 pernyataan TIDAK dijalankan ketika kerangka pengujian dijalankan karena tanda DEBUG tidak disetel saat kami menjalankan pengujian.
Chris Williams
27

Java Efektif, Edisi Kedua , di akhir Item 19 mencatat bahwa Anda dapat menggunakan impor statis jika Anda sering menggunakan konstanta dari kelas utilitas. Saya pikir prinsip ini akan berlaku untuk impor statis dari kedua konstanta dan metode.

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

Ini memiliki kelebihan dan kekurangan. Itu membuat kode sedikit lebih mudah dibaca dengan mengorbankan beberapa informasi langsung tentang di mana metode itu didefinisikan. Namun, IDE yang baik akan membiarkan Anda beralih ke definisi, jadi ini bukan masalah.

Anda masih harus menggunakan ini dengan hemat, dan hanya jika Anda menemukan diri Anda menggunakan sesuatu dari file yang diimpor berkali-kali.

Sunting: Diperbarui agar lebih spesifik untuk metode, karena itulah yang dimaksud dengan pertanyaan ini. Prinsip ini berlaku terlepas dari apa yang diimpor (konstanta atau metode).

Rob Hruska
sumber
1
Pertanyaan saya adalah tentang metode impor statis , bukan bidang.
Variabel Miserable
7
Mungkin UtilityClassWithFrequentlyUsedMethodsperlu dipersingkat.
Steve Kuo
5
@SteveKuo jelas kurang dari InternalFrameTitlePaneMaximizeButtonWindowNotFocusedState : P
Anirban Nag 'tintinmj'
@ Rob-Hruska Tidak bisakah saya membungkus metode impor statis atau bidang dalam metode atau bidang baru jika saya berencana untuk sering menggunakannya? Apakah itu memungkinkan saya untuk tidak mengimpor secara statis? seperti: double myPI = Math.PI;dan kemudian saya bisa saya terus merujuk myPIalih-alih Math.PI.
Abdul
@Abdul - Ya, Anda bisa melakukan itu.
Rob Hruska
15

Saya setuju bahwa mereka bisa bermasalah dari sudut pandang keterbacaan dan harus digunakan dengan hemat. Tetapi ketika menggunakan metode statis umum, mereka benar-benar dapat meningkatkan keterbacaan. Misalnya, dalam kelas pengujian JUnit, metode seperti assertEqualsitu jelas dari mana asalnya. Demikian pula untuk metode dari java.lang.Math.

Joel
sumber
5
Dan apa buruknya melihat Math.round (d) versus round (d)?
Steve Kuo
6
@SteveKuo - untuk alasan yang sama bahwa matematikawan menggunakan nama variabel satu huruf saat memanipulasi rumus: ada kalanya nama yang lebih panjang mengganggu keterbacaan pernyataan keseluruhan. Pertimbangkan rumus yang melibatkan beberapa fungsi trigonometri. Formula matematika mudah digenggam: sin x cos y + cos x sin y. Di Jawa menjadi: Math.sin(x) * Math.cos(y) + Math.cos(x) * Math.sin(y). Mengerikan untuk dibaca.
ToolmakerSteve
@ToolmakerSteve, itulah mengapa saya sangat merindukan usingarahan di C ++: mereka bisa lokal .
Franklin Yu
15

Saya pikir impor statis sangat berguna untuk menghapus nama kelas yang berlebihan saat menggunakan kelas utils seperti Arraysdan Assertions.

Tidak yakin mengapa tetapi Ross melewatkan kalimat terakhir yang menyebutkan ini dalam dokumentasi yang dia referensikan .

Jika digunakan dengan tepat, impor statis dapat membuat program Anda lebih mudah dibaca, dengan menghapus boilerplate pengulangan nama kelas.

Pada dasarnya disalin dari blog ini: https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

Jadi contohnya:

Pernyataan dalam pengujian

Ini adalah kasus paling jelas yang menurut saya kita semua setujui

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

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

Kelas utilitas dan enum

Nama kelas dapat dihapus dalam banyak kasus saat menggunakan kelas utils membuat kode lebih mudah dibaca

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

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

Paket java.time memiliki beberapa kasus yang harus digunakan

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

Contoh kapan TIDAK digunakan

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

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

Saya sering menggunakannya untuk Color.

static import java.awt.Color.*;

Sangat tidak mungkin bahwa warna akan tertukar dengan warna lain.

jjnguy
sumber
1
Itu adalah salah satu kasus penggunaan terbaik yang pernah saya lihat berbeda dari yang lama JUnit / Hamcrest / TestNG.
kevinarpe
4

Saya merekomendasikan penggunaan impor statis saat menggunakan OpenGL dengan Java, yang adalah penggunaan-kasus jatuh ke dalam "penggunaan berat konstanta dari kelas utilitas" kategori

Pertimbangkan itu

import static android.opengl.GLES20.*;

memungkinkan Anda untuk mem-port kode C asli dan menulis sesuatu yang dapat dibaca seperti:

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

bukannya keburukan umum yang tersebar luas itu:

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);
Batu api
sumber
2

Impor statis adalah satu-satunya fitur Java "baru" yang belum pernah saya gunakan dan tidak bermaksud untuk digunakan, karena masalah yang baru saja Anda sebutkan.

Bombe
sumber
Terima kasih Bombe. Yah, saya percaya mereka lebih masuk akal bahwa harus memperluas dan antarmuka yang hanya berisi sekumpulan final statis.
Variabel Menyedihkan
2

Saya menggunakan 'import static java.lang.Math. *' Saat mem-porting kode matematika yang berat dari C / C ++ ke java. Metode matematika memetakan 1 ke 1 dan membuat diffing kode porting lebih mudah tanpa kualifikasi nama kelas.

Fracdroid
sumber
2

Saya merasa ini sangat nyaman saat menggunakan kelas Utilitas.

Misalnya, daripada menggunakan: if(CollectionUtils.isNotEmpty(col))

Saya malah bisa:

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

IMO mana yang meningkatkan keterbacaan kode ketika saya menggunakan utilitas ini beberapa kali dalam kode saya.

Yeikel
sumber
2

Berbicara tentang pengujian unit: kebanyakan orang menggunakan impor statis untuk berbagai metode statis yang disediakan oleh kerangka kerja tiruan , seperti when()atau verify().

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

Dan tentu saja, saat menggunakan satu-satunya pernyataan yang harus Anda gunakan, assertThat()akan berguna untuk mengimpor secara statis pencocok hamcrest yang diperlukan, seperti di:

import static org.hamcrest.Matchers.*;
GhostCat
sumber
1

Mereka berguna untuk mengurangi bertele-tele, terutama dalam kasus di mana ada banyak metode impor yang dipanggil, dan perbedaan antara metode lokal dan impor jelas.

Salah satu contoh: kode yang melibatkan banyak referensi ke java.lang.Math

Lain: Kelas pembuat XML di mana memasukkan nama kelas ke setiap referensi akan menyembunyikan struktur yang sedang dibangun

kdgregory
sumber
1

Saya pikir impor statis rapi untuk NLS dalam gaya gettext.

import static mypackage.TranslatorUtil._;

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

Ini menandai string sebagai string yang harus diekstraksi dan menyediakan cara yang mudah dan bersih untuk mengganti string dengan terjemahannya.

Matthias Wuttke
sumber
1

Impor statis IMO adalah fitur yang cukup bagus. Memang benar bahwa ketergantungan yang besar pada impor statis membuat kode tidak dapat dibaca dan sulit untuk memahami kelas mana yang dimiliki metode atau atribut statis. Namun, menurut pengalaman saya, ini menjadi fitur yang dapat digunakan terutama saat mendesain Utilkelas yang menyediakan beberapa metode dan atribut statis. Ketidakjelasan yang muncul setiap kali menyediakan impor statis dapat dielakkan dengan menetapkan standar kode. Dalam pengalaman saya dalam sebuah perusahaan, pendekatan ini dapat diterima dan membuat kode lebih bersih serta mudah dipahami. Lebih disukai saya memasukkan _karakter di depan metode statis dan atribut statis (entah bagaimana diadopsi dari C). Rupanya pendekatan ini melanggar standar penamaan Java tetapi memberikan kejelasan kode. Misalnya, jika kita memiliki kelas 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){

    }
}

Dalam hal ini impor statis memberikan kejelasan dan struktur kode terlihat lebih elegan bagi saya:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

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

Segera seseorang dapat mengetahui metode atau atribut mana yang berasal dari impor statis dan menyembunyikan informasi dari kelas tempatnya. Saya tidak menyarankan menggunakan impor statis untuk kelas yang merupakan bagian integral dari modul dan menyediakan metode statis dan non-statis karena dalam kasus ini, penting untuk mengetahui kelas mana yang menyediakan fungsionalitas statis tertentu.

eldjon
sumber
Terima kasih atas saran penamaan ulang. BTW, garis bawah di depan secara tradisional digunakan di beberapa lingkungan untuk menamai metode / bidang pribadi. Saya sedang mempertimbangkan konvensi yang dimodifikasi, seperti H_untuk impor dari Helperkelas utilitas yang saya miliki, atau C_untuk Common, atau U_untuk Utility. Sebagai alternatif, saya telah mempertimbangkan untuk menggunakan satu atau dua nama kelas karakter untuk kelas yang banyak digunakan ini, tetapi khawatir itu kadang-kadang mungkin bertentangan dengan nama lokal - memiliki beberapa kode warisan dengan nama metode huruf besar.
ToolmakerSteve
-1

Anda perlu menggunakannya saat:

  • Anda ingin menggunakan switchpernyataan dengan nilai enum
  • Anda ingin membuat kode Anda sulit dimengerti
davetron5000
sumber
9
Ini tidak benar. (1) Anda dapat menggunakan konstanta enum dengan sangat baik tanpa impor statisnya. (2) Impor statis, katakanlah, metode kelas JUnit Assert jelas seperti bel. "assertTrue (...)" sama terbaca seperti "Assert.assertTrue (...)", mungkin lebih.
Alan Krueger
5
jika Anda memiliki 5 impor statis dalam kelas baris 500, sangat sulit untuk mengetahui dari mana asal metode.
davetron5000
4
+1 untuk saat Anda ingin membuat kode Anda sulit dimengerti :)
Miserable Variable
-5

Saya menggunakannya kapan pun saya bisa. Saya memiliki pengaturan IntelliJ untuk mengingatkan saya jika saya lupa. Saya pikir ini terlihat jauh lebih bersih daripada nama paket yang sepenuhnya memenuhi syarat.

Javamann
sumber
13
Anda sedang memikirkan impor reguler. Impor statis memungkinkan Anda merujuk ke anggota kelas tanpa memasukkan nama kelas kepada mereka, misalnya static import java.lang.system.out; out.println ("foo"); // bukannya System.out.println ("foo");
sk.
Sekarang ini adalah penjelasan yang sangat bagus tentang impor statis ...
sayang