java - मरज - इस इश्क में मर जावा



सरणी[idx++]+= "a" जावा 8 में एक बार, लेकिन जावा 9 और 10 में दो बार आईडीएक्स क्यों बढ़ाती है? (1)

यह JDK 9 से शुरू होने वाले javac में एक बग है (जिसमें स्ट्रिंग संघनन के संबंध में कुछ बदलाव किए गए थे, जो मुझे संदेह है कि समस्या का हिस्सा है), JDK-8204322 । यदि आप पंक्ति के लिए इसी बायोटेक को देखते हैं:

array[i++%size] += i + " ";

यह है:

  21: aload_2
  22: iload_3
  23: iinc          3, 1
  26: iload_1
  27: irem
  28: aload_2
  29: iload_3
  30: iinc          3, 1
  33: iload_1
  34: irem
  35: aaload
  36: iload_3
  37: invokedynamic #5,  0 // makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;
  42: aastore

जहां अंतिम aaload सरणी से वास्तविक भार है। हालाँकि, भाग

  21: aload_2             // load the array reference
  22: iload_3             // load 'i'
  23: iinc          3, 1  // increment 'i' (doesn't affect the loaded value)
  26: iload_1             // load 'size'
  27: irem                // compute the remainder

जो मोटे तौर पर एक्सप्रेशन array[i++%size] (वास्तविक लोड और स्टोर से घटा) से मेल खाती है, दो बार है। यह गलत है, जैसा कि युक्ति jls-15.26.2 में कहती है:

E1 op= E2 फॉर्म का एक यौगिक असाइनमेंट अभिव्यक्ति E1 = (T) ((E1) op (E2)) बराबर है, जहां T E1 का प्रकार है, सिवाय इसके कि E1 का मूल्यांकन केवल एक बार किया जाता है।

तो, अभिव्यक्ति array[i++%size] += i + " "; , भाग array[i++%size] का केवल एक बार मूल्यांकन किया जाना चाहिए। लेकिन इसका मूल्यांकन दो बार किया जाता है (एक बार लोड के लिए, और एक बार स्टोर के लिए)।

तो हाँ, यह एक बग है।

कुछ अपडेट:

बग JDK 11 में तय किया गया है और JDK 10 का बैक-पोर्ट होगा (लेकिन JDK 9 नहीं, क्योंकि यह अब सार्वजनिक अपडेट प्राप्त नहीं करता है )।

अलेक्सी शिपिलेव ने जेबीएस पेज पर (और @DidierL यहाँ टिप्पणियों में) उल्लेख किया है:

समाधान: -XDstringConcat=inline साथ संकलित करें

यह StringBuilder करने के लिए StringBuilder का उपयोग करने के लिए वापस आ जाएगा, और बग नहीं है।

एक चुनौती के लिए, एक साथी कोड गोल्फर ने निम्नलिखित कोड लिखा :

import java.util.*;
public class Main {
  public static void main(String[] args) {
    int size = 3;
    String[] array = new String[size];
    Arrays.fill(array, "");
    for(int i = 0; i <= 100; ) {
      array[i++%size] += i + " ";
    }
    for(String element: array) {
      System.out.println(element);
    }
  }
}

जावा 8 में इस कोड को चलाने पर, हमें निम्न परिणाम मिलते हैं:

1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100 
2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59 62 65 68 71 74 77 80 83 86 89 92 95 98 101 
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 

जावा 10 में इस कोड को चलाने पर, हमें निम्न परिणाम मिलते हैं:

2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 

नंबर 10 जावा के उपयोग से पूरी तरह से बंद है। तो यहां क्या हो रहा है? यह जावा 10 में एक बग है?

टिप्पणियों से अप का पालन करें:

  • जब जावा 9 या बाद में संकलित किया जाता है (तो हमने इसे जावा 10 में पाया)। इस कोड को जावा 8 पर संकलित करना, फिर जावा 9 या किसी भी बाद के संस्करण में चलना, जिसमें जावा 11 जल्दी पहुंच भी शामिल है, अपेक्षित परिणाम देता है।
  • इस तरह का कोड गैर-मानक है, लेकिन कल्पना के अनुसार मान्य है। यह केविन क्रूज़सेन द्वारा एक गोल्फ चुनौती में एक चर्चा में पाया गया था, इसलिए अजीब उपयोग के मामले का सामना करना पड़ा।
  • डिडियर एल को पता चला कि इस मुद्दे को बहुत छोटे और अधिक समझने योग्य कोड के साथ पुन: प्रस्तुत किया जा सकता है:

    class Main {
      public static void main(String[] args) {
        String[] array = { "" };
        array[test()] += "a";
      }
      static int test() {
        System.out.println("evaluated");
        return 0;
      }
    }

    जावा 8 में संकलित होने पर परिणाम:

    evaluated

    जावा 9 और 10 में संकलित होने पर परिणाम:

    evaluated
    evaluated
  • यह मुद्दा स्ट्रिंग संकेतन और असाइनमेंट ऑपरेटर ( += ) तक सीमित है जो कि साइड इफेक्ट के साथ एक अभिव्यक्ति के साथ है, बाएं ऑपरेंड के रूप में, जैसे कि array[test()]+="a" , array[ix++]+="a" , test()[index]+="a" , या test().field+="a" । स्ट्रिंग संघनन को सक्षम करने के लिए, कम से कम एक पक्ष में String होना आवश्यक है। अन्य प्रकारों या निर्माणों पर इसे पुन: पेश करने की कोशिश विफल रही।






java-10