Mendeklarasikan variabel di dalam atau di luar loop

236

Mengapa hal berikut ini berfungsi dengan baik?

String str;
while (condition) {
    str = calculateStr();
    .....
}

Tapi yang ini dikatakan berbahaya / salah:

while (condition) {
    String str = calculateStr();
    .....
}

Apakah perlu mendeklarasikan variabel di luar loop?

Harry Joy
sumber

Jawaban:

289

Ruang lingkup variabel lokal harus selalu sekecil mungkin.

Dalam contoh saya nyana stryang tidak digunakan di luar whilelingkaran, jika tidak, anda tidak akan mengajukan pertanyaan, karena menyatakan itu dalamwhile lingkaran tidak akan menjadi pilihan, karena itu tidak akan mengkompilasi.

Jadi, karena strini tidak digunakan di luar loop, ruang lingkup terkecil yang mungkin untuk strini dalam sementara lingkaran.

Jadi, jawabannya adalah empatik yang strmutlak harus dinyatakan dalam loop sementara. Tidak ada, tidak ada, dan tidak ada.

Satu-satunya kasus di mana aturan ini mungkin dilanggar adalah jika karena alasan tertentu itu sangat penting bahwa setiap siklus jam harus diperas dari kode, dalam hal ini Anda mungkin ingin mempertimbangkan instantiasi sesuatu dalam lingkup luar dan menggunakannya kembali daripada instantiasi ulang pada setiap iterasi dari ruang lingkup dalam. Namun, ini tidak berlaku untuk contoh Anda, karena kekekalan string di java: contoh baru dari str akan selalu dibuat di awal loop Anda dan harus dibuang di akhir, jadi ada tidak ada kemungkinan untuk mengoptimalkan di sana.

Sunting: (menyuntikkan komentar saya di bawah dalam jawaban)

Bagaimanapun, cara yang tepat untuk melakukan sesuatu adalah dengan menulis semua kode Anda dengan benar, menetapkan persyaratan kinerja untuk produk Anda, mengukur produk akhir Anda terhadap persyaratan ini, dan jika tidak memuaskannya, maka optimalkan segala sesuatunya. Dan yang biasanya terjadi adalah Anda menemukan cara untuk menyediakan beberapa optimasi algoritmik yang bagus dan formal hanya dalam beberapa tempat yang membuat program kami memenuhi persyaratan kinerjanya alih-alih harus menjelajahi seluruh basis kode Anda dan men-tweak dan meretas hal-hal di Untuk memeras siklus jam di sana-sini.

Mike Nakis
sumber
2
Pertanyaan pada paragraf terakhir: Jika itu adalah String lain maka yang tidak berubah maka apakah itu mempengaruhi?
Harry Joy
1
@ HarryJoy Ya, tentu saja, ambil contoh StringBuilder, yang bisa berubah. Jika Anda menggunakan StringBuilder untuk membuat string baru di setiap iterasi loop, maka Anda dapat mengoptimalkan berbagai hal dengan mengalokasikan StringBuilder di luar loop. Tapi tetap saja, ini bukan praktik yang disarankan. Jika Anda melakukannya tanpa alasan yang sangat bagus, itu adalah optimasi prematur.
Mike Nakis
7
@ HarryJoy Cara yang tepat untuk melakukan sesuatu adalah dengan menulis semua kode Anda dengan benar , menetapkan persyaratan kinerja untuk produk Anda, mengukur produk akhir Anda terhadap persyaratan ini, dan jika tidak memuaskan, maka optimalkan beberapa hal. Dan tahukah Anda? Anda biasanya dapat memberikan beberapa optimasi algoritmik yang bagus dan formal hanya di beberapa tempat yang akan melakukan trik alih-alih harus menjelajahi seluruh basis kode Anda dan men-tweak dan meretas hal-hal untuk menekan siklus jam di sana-sini.
Mike Nakis
2
@ MikeNakis saya pikir Anda berpikir dalam lingkup yang sangat sempit.
Siten
5
Soalnya, CPU multi-gigahertz, multi-core, pipelined, multi-level-memory-cache modern memungkinkan kami untuk fokus mengikuti praktik terbaik tanpa harus khawatir tentang siklus clock. Selain itu, optimasi hanya disarankan jika dan hanya jika telah ditentukan bahwa itu perlu, dan ketika diperlukan, beberapa tweak yang sangat lokal biasanya akan mencapai kinerja yang diinginkan, sehingga tidak perlu membuang sampah sembarangan semua kode kami dengan sedikit peretasan atas nama kinerja.
Mike Nakis
293

Saya membandingkan kode byte dari dua contoh (serupa) itu:

Mari kita lihat 1. contoh :

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

setelah itu javac Test.java, javap -c TestAnda akan mendapatkan:

public class inside.Test extends java.lang.Object{
public inside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Mari kita lihat 2. contoh :

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

setelah itu javac Test.java, javap -c TestAnda akan mendapatkan:

public class outside.Test extends java.lang.Object{
public outside.Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

Pengamatan menunjukkan bahwa tidak ada perbedaan di antara dua contoh itu. Ini adalah hasil dari spesifikasi JVM ...

Tetapi atas nama praktik pengkodean terbaik, disarankan untuk mendeklarasikan variabel dalam ruang lingkup sekecil mungkin (dalam contoh ini berada di dalam loop, karena ini adalah satu-satunya tempat di mana variabel digunakan).

PrimosK
sumber
3
Ini adalah hasil dari JVM Soecification, bukan 'optimasi kompiler'. Slot stack yang dibutuhkan oleh suatu metode dialokasikan pada saat masuk ke metode. Begitulah cara bytecode ditentukan.
Marquis of Lorne
2
@Arhimed ada satu alasan lagi untuk meletakkannya di dalam loop (atau hanya blok '{}'): kompiler akan menggunakan kembali memori yang dialokasikan dalam bingkai tumpukan untuk variabel dalam lingkup lain jika Anda mendeklarasikan dalam lingkup lain beberapa variabel lebih .
Serge
1
Jika perulangan melalui daftar objek data, maka apakah akan ada bedanya untuk sebagian besar data? Mungkin 40 ribu.
Mithun Khatri
7
Bagi Anda finalpecinta: menyatakan strseperti finaldalam insidepaket juga tidak ada bedanya =)
skia.heliou
27

Mendeklarasikan objek dalam lingkup terkecil meningkatkan keterbacaan .

Kinerja tidak masalah untuk kompiler saat ini. (Dalam skenario ini)
Dari perspektif pemeliharaan, opsi ke-2 lebih baik.
Deklarasikan dan inisialisasi variabel di tempat yang sama, dalam ruang lingkup sesempit mungkin.

Seperti yang dikatakan Donald Ervin Knuth :

"Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan"

yaitu) situasi di mana seorang programmer memungkinkan pertimbangan kinerja mempengaruhi desain sepotong kode. Ini dapat menghasilkan desain yang tidak sebersih mungkin atau kode yang tidak benar, karena kode rumit oleh optimasi dan programmer terganggu dengan optimalisasi .

Chandra Sekhar
sumber
1
"Opsi ke-2 memiliki kinerja yang sedikit lebih cepat" => sudahkah Anda mengukurnya? Menurut salah satu jawaban, bytecode sama sehingga saya tidak melihat bagaimana kinerja bisa berbeda.
assylias
Maaf, tapi itu bukan cara yang tepat untuk menguji kinerja program java (dan bagaimana Anda bisa menguji kinerja loop tak terbatas?)
assylias
Saya setuju dengan poin Anda yang lain - hanya saja saya percaya bahwa tidak ada perbedaan kinerja.
assylias
11

jika Anda ingin menggunakan strlooop luar juga; mendeklarasikannya di luar. jika tidak, versi ke-2 baik-baik saja.

Azodious
sumber
11

Silakan lewati ke jawaban yang diperbarui ...

Bagi mereka yang peduli dengan kinerja, keluarkan System.out dan batasi loop hingga 1 byte. Menggunakan double (test 1/2) dan menggunakan String (3/4) waktu yang berlalu dalam milidetik diberikan di bawah ini dengan Windows 7 Professional 64 bit dan JDK-1.7.0_21. Bytecodes (juga diberikan di bawah ini untuk test1 dan test2) tidak sama. Saya terlalu malas untuk menguji dengan benda yang bisa berubah & relatif kompleks.

dua kali lipat

Test1 mengambil: 2710 msecs

Test2 mengambil: 2790 msecs

String (ganti saja double dengan string dalam tes)

Test3 mengambil: 1200 msecs

Test4 mengambil: 3000 msecs

Mengompilasi dan mendapatkan bytecode

javac.exe LocalTest1.java

javap.exe -c LocalTest1 > LocalTest1.bc


public class LocalTest1 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        double test;
        for (double i = 0; i < 1000000000; i++) {
            test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }

}

public class LocalTest2 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        for (double i = 0; i < 1000000000; i++) {
            double test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }
}


Compiled from "LocalTest1.java"
public class LocalTest1 {
  public LocalTest1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore        5
       7: dload         5
       9: ldc2_w        #3                  // double 1.0E9d
      12: dcmpg
      13: ifge          28
      16: dload         5
      18: dstore_3
      19: dload         5
      21: dconst_1
      22: dadd
      23: dstore        5
      25: goto          7
      28: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      31: lstore        5
      33: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: new           #6                  // class java/lang/StringBuilder
      39: dup
      40: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      43: ldc           #8                  // String Test1 Took:
      45: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: lload         5
      50: lload_1
      51: lsub
      52: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      55: ldc           #11                 // String  msecs
      57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      60: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      63: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: return
}


Compiled from "LocalTest2.java"
public class LocalTest2 {
  public LocalTest2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore_3
       6: dload_3
       7: ldc2_w        #3                  // double 1.0E9d
      10: dcmpg
      11: ifge          24
      14: dload_3
      15: dstore        5
      17: dload_3
      18: dconst_1
      19: dadd
      20: dstore_3
      21: goto          6
      24: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      27: lstore_3
      28: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: new           #6                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      38: ldc           #8                  // String Test1 Took:
      40: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: lload_3
      44: lload_1
      45: lsub
      46: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      49: ldc           #11                 // String  msecs
      51: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

JAWABAN TERBARU

Benar-benar tidak mudah untuk membandingkan kinerja dengan semua optimisasi JVM. Namun, itu agak mungkin. Tes yang lebih baik dan hasil terperinci dalam Google Caliper

  1. Beberapa detail di blog: Haruskah Anda mendeklarasikan variabel di dalam loop atau sebelum loop?
  2. Repositori GitHub: https://github.com/gunduru/jvdt
  3. Hasil Uji untuk kasing ganda dan loop 100M (dan ya semua detail JVM): https://microbenchmarks.appspot.com/runs/b1cef8d1-0e2c-4120-be61-a99faff625b4

Dideklarasikan Sebelum 1,759,209 Dideklarasikan Di dalam 2,242.308

  • DideklarasikanSebelum 1,759.209 ns
  • Dideklarasikan Di dalam 2,242.308 ns

Kode Uji Parsial untuk Deklarasi rangkap

Ini tidak identik dengan kode di atas. Jika Anda hanya mengkode loop dummy, JVM akan melewatkannya, jadi setidaknya Anda perlu menetapkan dan mengembalikan sesuatu. Ini juga direkomendasikan dalam dokumentasi Caliper.

@Param int size; // Set automatically by framework, provided in the Main
/**
* Variable is declared inside the loop.
*
* @param reps
* @return
*/
public double timeDeclaredInside(int reps) {
    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Declaration and assignment */
        double test = i;

        /* Dummy assignment to fake JVM */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

/**
* Variable is declared before the loop.
*
* @param reps
* @return
*/
public double timeDeclaredBefore(int reps) {

    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Actual test variable */
    double test = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Assignment */
        test = i;

        /* Not actually needed here, but we need consistent performance results */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

Ringkasan: dideklarasikanSebelum menunjukkan kinerja yang lebih baik - sangat kecil - dan itu bertentangan dengan prinsip ruang lingkup terkecil. JVM seharusnya melakukan ini untuk Anda

Onur Günduru
sumber
Metodologi pengujian tidak valid, dan Anda tidak memberikan penjelasan apa pun tentang hasil Anda.
Marquis of Lorne
1
@ EJP Ini harus cukup jelas bagi mereka yang memiliki minat pada subjek. Metodologi diambil dari jawaban PrimosK untuk memberikan informasi yang lebih bermanfaat. Sejujurnya saya tidak tahu bagaimana meningkatkan jawaban ini, mungkin Anda dapat mengklik edit dan menunjukkan kepada kami bagaimana melakukannya dengan benar?
Onur Günduru
2
1) Java Bytecode dioptimalkan (disusun ulang, diciutkan, dll) pada saat runtime, jadi jangan terlalu peduli tentang apa yang ditulis pada file .class. 2) ada 1.000.000.000 run untuk mendapatkan kemenangan kinerja 2,8s, jadi itu sekitar 2,8ns per run vs gaya pemrograman yang aman dan tepat. Pemenang yang jelas bagi saya. 3) Karena Anda tidak memberikan informasi tentang pemanasan, timing Anda tidak berguna.
Hardcoded
@Hardcoded tes yang lebih baik / pembandingan mikro dengan caliper hanya untuk loop ganda dan 100M. Hasil online, jika Anda ingin kasus lain merasa bebas untuk diedit.
Onur Günduru
Terima kasih, ini menghilangkan poin 1) dan 3). Tetapi bahkan jika waktu naik hingga ~ 5ns per siklus, ini masih waktu untuk diabaikan. Secara teori, ada potensi optimisasi kecil, dalam kenyataannya hal-hal yang Anda lakukan per siklus biasanya jauh lebih mahal. Jadi potensi maksimum akan menjadi beberapa detik dalam beberapa menit atau bahkan berjam-jam. Ada opsi lain dengan potensi lebih tinggi yang tersedia (misalnya Fork / Bergabung, Paralel paralel) yang akan saya periksa sebelum menghabiskan waktu untuk jenis optimasi tingkat rendah ini.
Hardcoded
7

Salah satu solusi untuk masalah ini bisa dengan menyediakan ruang lingkup variabel yang merangkum loop sementara:

{
  // all tmp loop variables here ....
  // ....
  String str;
  while(condition){
      str = calculateStr();
      .....
  }
}

Mereka akan secara otomatis kehilangan referensi ketika lingkup luar berakhir.

Morten Madsen
sumber
6

Di dalam, semakin sedikit ruang lingkup variabel terlihat menjadi lebih baik.

Jan Zyka
sumber
5

Jika Anda tidak perlu menggunakan strafter loop sementara (lingkup terkait) maka kondisi kedua yaitu

  while(condition){
        String str = calculateStr();
        .....
    }

lebih baik karena jika Anda mendefinisikan objek pada stack hanya jika conditionitu benar. Yaitu menggunakannya jika Anda membutuhkannya

Cratylus
sumber
2
Perhatikan bahwa bahkan dalam varian pertama, tidak ada objek yang dibangun jika kondisinya salah.
Philipp Wendler
@ Phillip: Ya Anda benar. Salahku. Saya berpikir seperti sekarang. Bagaimana menurut Anda?
Cratylus
1
Yah "mendefinisikan objek pada stack" adalah istilah yang agak aneh di dunia Java. Juga, mengalokasikan variabel pada stack biasanya adalah noop saat runtime, jadi mengapa repot-repot? Pelingkupan untuk membantu programmer adalah masalah sebenarnya.
Philipp Wendler
3

Saya pikir sumber terbaik untuk menjawab pertanyaan Anda adalah posting berikut:

Perbedaan antara mendeklarasikan variabel sebelum atau dalam lingkaran?

Menurut pemahaman saya, hal ini tergantung pada bahasa. IIRC Java mengoptimalkan ini, jadi tidak ada perbedaan, tetapi JavaScript (misalnya) akan melakukan alokasi memori keseluruhan setiap kali dalam loop. Di Jawa khususnya saya pikir yang kedua akan berjalan lebih cepat ketika melakukan profil.

Naveen Goyal
sumber
3

Seperti banyak orang tunjukkan,

String str;
while(condition){
    str = calculateStr();
    .....
}

adalah TIDAK lebih baik dari ini:

while(condition){
    String str = calculateStr();
    .....
}

Jadi jangan mendeklarasikan variabel di luar cakupannya jika Anda tidak menggunakannya kembali ...

Pavan
sumber
1
kecuali mungkin dengan cara ini: tautan
Dainius Kreivys
2

Mendeklarasikan String str di luar loop wile memungkinkannya direferensikan di dalam & di luar loop while. Mendeklarasikan String str di dalam loop sementara memungkinkan untuk hanya direferensikan di dalam loop sementara.

Jay Tomten
sumber
1

Variabel harus dinyatakan sedekat mungkin dengan tempat mereka digunakan.

Itu membuat RAII (Akuisisi Sumber Daya Adalah Inisialisasi) lebih mudah.

Itu membuat ruang lingkup variabel ketat. Ini memungkinkan pengoptimal bekerja lebih baik.

vikiiii
sumber
1

Menurut panduan Pengembangan Android Google, ruang lingkup variabel harus dibatasi. Silakan periksa tautan ini:

Batasi Cakupan Variabel

James Jithin
sumber
1

The strvariabel akan tersedia dan disediakan beberapa ruang di memori bahkan setelah beberapa saat dieksekusi di bawah kode.

 String str;
    while(condition){
        str = calculateStr();
        .....
    }

The strvariabel tidak akan tersedia dan juga memori akan dirilis yang dialokasikan untuk strvariabel di bawah kode.

while(condition){
    String str = calculateStr();
    .....
}

Jika kita mengikuti yang kedua tentunya ini akan mengurangi memori sistem kita dan meningkatkan kinerja.

Ganesa Vijayakumar
sumber
0

Mendeklarasikan di dalam loop membatasi ruang lingkup variabel masing-masing. Itu semua tergantung pada persyaratan proyek pada ruang lingkup variabel.

ab02
sumber
0

Sungguh, pertanyaan yang disebutkan di atas adalah masalah pemrograman. Bagaimana Anda ingin memprogram kode Anda? Di mana Anda membutuhkan 'STR' untuk diakses? Tidak ada gunanya mendeklarasikan variabel yang digunakan secara lokal sebagai variabel global. Dasar-dasar pemrograman saya percaya.

Abhishek Bhandari
sumber
-1

Dua contoh ini menghasilkan hal yang sama. Namun, yang pertama memberi Anda menggunakan strvariabel di luar loop sementara; yang kedua bukan.

olyanren
sumber
-1

Peringatan untuk hampir semua orang dalam pertanyaan ini: Berikut adalah contoh kode di mana di dalam loop itu dapat dengan mudah 200 kali lebih lambat di komputer saya dengan Java 7 (dan konsumsi memori juga sedikit berbeda). Tapi ini tentang alokasi dan bukan hanya ruang lingkup.

public class Test
{
    private final static int STUFF_SIZE = 512;
    private final static long LOOP = 10000000l;

    private static class Foo
    {
        private long[] bigStuff = new long[STUFF_SIZE];

        public Foo(long value)
        {
            setValue(value);
        }

        public void setValue(long value)
        {
            // Putting value in a random place.
            bigStuff[(int) (value % STUFF_SIZE)] = value;
        }

        public long getValue()
        {
            // Retrieving whatever value.
            return bigStuff[STUFF_SIZE / 2];
        }
    }

    public static long test1()
    {
        long total = 0;

        for (long i = 0; i < LOOP; i++)
        {
            Foo foo = new Foo(i);
            total += foo.getValue();
        }

        return total;
    }

    public static long test2()
    {
        long total = 0;

        Foo foo = new Foo(0);
        for (long i = 0; i < LOOP; i++)
        {
            foo.setValue(i);
            total += foo.getValue();
        }

        return total;
    }

    public static void main(String[] args)
    {
        long start;

        start = System.currentTimeMillis();
        test1();
        System.out.println(System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        test2();
        System.out.println(System.currentTimeMillis() - start);
    }
}

Kesimpulan: Bergantung pada ukuran variabel lokal, perbedaannya bisa sangat besar, bahkan dengan variabel yang tidak terlalu besar.

Hanya mengatakan bahwa kadang-kadang, di luar atau di dalam loop itu penting.

rt15
sumber
1
Tentu, yang kedua lebih cepat, tetapi Anda melakukan hal yang berbeda: test1 menciptakan banyak Foo-Objects dengan array besar, test2 tidak. test2 menggunakan kembali objek Foo yang sama berulang-ulang, yang mungkin berbahaya di lingkungan multithreaded.
Hardcoded
Berbahaya di lingkungan multithreaded ??? Tolong jelaskan mengapa. Kami berbicara tentang variabel lokal. Itu dibuat pada setiap panggilan metode.
rt15
Jika Anda meneruskan Foo-Object ke operasi yang memproses data secara tidak sinkron, operasi mungkin masih bekerja pada instance-Foo saat Anda mengubah data di dalamnya. Bahkan tidak perlu multithreaded untuk memiliki efek samping. Jadi menggunakan kembali instance cukup berbahaya, ketika Anda tidak tahu siapa yang masih menggunakan instance
Hardcoded
P: Metode setValue Anda seharusnya bigStuff[(int) (value % STUFF_SIZE)] = value;(Coba nilai 2147483649L)
Hardcoded
Berbicara tentang efek samping: Sudahkah Anda membandingkan hasil metode Anda?
Hardcoded
-1

Saya pikir ukuran objek juga penting. Dalam salah satu proyek saya, kami telah mendeklarasikan dan menginisialisasi array dua dimensi besar yang membuat aplikasi membuang pengecualian di luar memori. Kami memindahkan deklarasi keluar dari loop sebagai gantinya dan menghapus array pada awal setiap iterasi.

Sanjit
sumber
-2

Anda berisiko NullPointerExceptionjika calculateStr()metode Anda mengembalikan nol dan kemudian Anda mencoba memanggil metode di str.

Secara umum, hindari memiliki variabel dengan nilai nol . Ngomong-ngomong, atribut kelas lebih kuat.

Rémi Doolaeghe
sumber
2
Ini tidak ada hubungannya dengan pertanyaan. Probabilitas NullPointerException (pada panggilan fungsi di masa depan) tidak akan bergantung pada bagaimana variabel dideklarasikan.
Gurun Es
1
Saya kira tidak, karena pertanyaannya adalah "Apa cara terbaik untuk melakukannya?". IMHO saya lebih suka kode yang lebih aman.
Rémi Doolaeghe
1
Tidak ada risiko a. NullPointerException.Jika kode ini dicoba return str;akan mengalami kesalahan kompilasi.
Marquis of Lorne