কেন অ্যারে [আইডিএক্স ++] + = “এ” জাভা 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.