কেন অ্যারে [আইডিএক্স ++] + = “এ” জাভা 8 এ একবার জাভা 9 এবং 10 এ একবার আইডেক্স বাড়িয়েছে?


751

একটি চ্যালেঞ্জের জন্য, একজন সহকর্মী গল্ফার নিম্নলিখিত কোডগুলি লিখেছিলেন :

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 ব্যবহার করে পুরোপুরি বন্ধ রয়েছে So তাই এখানে কী হচ্ছে? এটি কি জাভা 10-এ একটি বাগ আছে?

মন্তব্যগুলি থেকে অনুসরণ করুন:

  • জাভা 9 বা তার পরে সংকলিত হওয়ার পরে সমস্যাটি উপস্থিত হয় (আমরা এটি জাভা 10 তে পেয়েছি)। জাভা 8 এ এই কোডটি সংকলন করুন, তারপরে জাভা 9 বা জাভা 11 প্রারম্ভিক অ্যাক্সেস সহ পরবর্তী কোনও সংস্করণে চলমান প্রত্যাশিত ফলাফল দেয়।
  • এই জাতীয় কোডটি মানহীন, তবে অনুমান অনুসারে বৈধ। এটা তোলে মাধ্যমে পাওয়া গেছে কেভিন Cruijssen একটি একটি আলোচনা golfing চ্যালেঞ্জ , অত অদ্ভুত ব্যবহারের ক্ষেত্রে সম্মুখীন হয়েছে।
  • ডিডিয়ার এল আবিষ্কার করেছেন যে সমস্যাটি আরও ছোট এবং আরও বোঝার কোড সহ পুনরুত্পাদন করা যেতে পারে:

    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। অন্যান্য ধরণের বা নির্মাণের ক্ষেত্রে এটি পুনরুত্পাদন করার চেষ্টা ব্যর্থ হয়েছে।


5
মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
— স্যামুয়েল লিউ

13
@ জোলি জোকার এটি +=পরোক্ষ Stringরেফারেন্সগুলিতে সীমাবদ্ধ । সুতরাং প্রথমে, আপনার অ্যারে অবশ্যই একটি হতে হবে String[]। সমস্যার সাথে ঘটবে না int[], long[]বন্ধু এবং। তবে হ্যাঁ, আপনি মূলত ঠিক বলেছেন!
— অলিভিয়ার গ্রাগোয়ার

2
@ অলিভিয়ারগ্রগোয়ার অ্যারে হওয়ার দরকার নেই String[]। যদি এটি হয় Object[]এবং আপনি করেন তবে এটি array[expression] += "foo";একই রকম। তবে হ্যাঁ, এটা আদিম অ্যারে প্রযোজ্য নয়, যেমন ধরনের রেফারেন্স রাখা সক্ষম হওয়া আবশ্যক String( Object[], CharSequence[], Comparable[], ...), স্ট্রিং সংযুক্তকরণের ফল সঞ্চয় করতে।
— হোলার

30
এটি জেডিকে -8204322 বাগ আইডি বরাদ্দ করা হয়েছে ।
— স্টুয়ার্ট

1
@ স্টার্টমার্কস ধন্যবাদ! উত্তরে এটি সংহত করা হয়েছে: আমি প্রশ্নটি স্বাভাবিক বা ত্রুটিযুক্ত কিনা সে সম্পর্কে সত্যই একটি প্রশ্ন রাখতে চাইতাম। যদিও আমরা উত্তরটিতে বাগের আইডি সম্পর্কে আরও স্পষ্ট হতে পারি। আমি এখনই এটি খাপ খাই।
— অলিভিয়ার গ্রাগোয়ার

উত্তর:


625

এটি javacজেডিকে 9 থেকে শুরু করার একটি বাগ (যা স্ট্রিং কনটেন্টেশন সম্পর্কিত কিছু পরিবর্তন করেছে, যা আমি সন্দেহ করি যে এটি সমস্যার অংশ)), জেডকে -8204322 বাগ আইডিটির অধীনে দলটি নিশ্চিত করেছেjavac । আপনি যদি লাইনের জন্য সংশ্লিষ্ট বাইকোডটি দেখেন:

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]একবারে মূল্যায়ন করা উচিত। তবে এটি দুবার মূল্যায়ন করা হয় (একবার ভারের জন্য, এবং একবার স্টোরের জন্য)।

হ্যাঁ, এটি একটি বাগ।


কিছু আপডেট:

বাগটি জেডিকে ১১-এ স্থির করা হয়েছে এবং জেডিকে 10-তে একটি ব্যাক-পোর্ট থাকবে (তবে জেডিকে 9 নয়, যেহেতু এটি আর পাবলিক আপডেটগুলি গ্রহণ করে না )।

আলেকসি শিপিলিভ জেবিএস পৃষ্ঠায় উল্লেখ করেছেন (এবং @ ডিডিয়েরএল মন্তব্যগুলিতে):

কর্মক্ষেত্র: সংকলন -XDstringConcat=inline

এটি সম্মিলন করতে ব্যবহার করে ফিরে যাবে StringBuilderএবং এতে ত্রুটি নেই।


34
যাইহোক, এটি পুরো বাম পাশের অভিব্যক্তিতে প্রযোজ্য, কেবল সূচকটি সাব-এক্সপ্রেশন সরবরাহ করে না। এই প্রকাশটি নির্বিচারে জটিল হতে পারে। উদাহরণস্বরূপ দেখুন IntStream.range(0, 10) .peek(System.out::println).boxed().toArray()[0] += "";...
— হোলার

9
@ হোলজার বাম দিকে এমনকি অ্যারে জড়িত করার প্রয়োজন নেই, সমস্যাটি একটি সরল সমস্যা নিয়েও ঘটে test().field += "sth"।
— দিদিয়ের এল

44
এটি গুরুত্বপূর্ণ নয়, আচরণটি যেভাবেই হোক ভয়াবহভাবে ভেঙে গেছে, তবে প্রথম মূল্যায়নটি স্টোরের জন্য এবং দ্বিতীয়টি বোঝার জন্য, সুতরাং array[index++] += "x";পড়তে হবে array[index+1]এবং এতে লিখতে হবে array[index]…
— হোলগার

5
@ দ্য কোডার হ্যাঁ আমিও তাই মনে করি। জেডিকে 9 কোনও দীর্ঘমেয়াদী সমর্থন (এলটিএস) প্রকাশ নয়। জেডিকে ৮ ছিল, এবং পরবর্তী এলটিএসের প্রকাশটি জেডিকে ১১ here এখানে দেখুন: oracle.com/technetwork/java/javase/eol-135779.html নোট করুন যে জেডিকে 9 এর সর্বজনীন আপডেট মার্চ মাসে শেষ হয়েছিল।
— জর্ন ভার্নি

15
জেডিকে -8204322-এ, আলেক্সি শিপিলিভ -XDstringConcat=inlineযাদের প্রয়োজন তাদের জন্য একটি কার্যকরী হিসাবে সংকলন করার পরামর্শ দিলেন।
— দিদিয়ের এল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.