বুলিয়ান, শর্তসাপেক্ষ অপারেটর এবং অটোবক্সিং


132

কেন এই নিক্ষেপ NullPointerException

public static void main(String[] args) throws Exception {
    Boolean b = true ? returnsNull() : false; // NPE on this line.
    System.out.println(b);
}

public static Boolean returnsNull() {
    return null;
}

যখন এটি না

public static void main(String[] args) throws Exception {
    Boolean b = true ? null : false;
    System.out.println(b); // null
}

?

সমাধান প্রতিস্থাপন প্রণালী দ্বারা হয় falseদ্বারা Boolean.FALSEএড়াতে nullকরার unboxed হচ্ছে boolean--which সম্ভব নয়। তবে প্রশ্নটি নয়। প্রশ্ন কেন ? জেএলএস-এ এমন কোনও রেফারেন্স রয়েছে যা এই আচরণটি নিশ্চিত করে, বিশেষত ২ য় মামলার?


28
বাহ, অটোবক্সিং একটি অন্তহীন উত্স ... এর ... জাভা প্রোগ্রামারটির জন্য আশ্চর্য, তাই না? :-)
লিওনব্লয়

আমারও একই সমস্যা ছিল এবং আমার অবাক করে দিয়েছিল যে এটি ওপেনজেডিকে ভিএম-তে ব্যর্থ হয়েছে তবে হটস্পট ভিএম-এ কাজ করেছে ... একবার লিখুন, যে কোনও জায়গায় চালান!
krod

উত্তর:


92

পার্থক্যটি হ'ল returnsNull()পদ্ধতির সুস্পষ্ট ধরণেরটি সংকলনের সময় প্রকাশের স্থির টাইপকে প্রভাবিত করে:

E1: `true ? returnsNull() : false` - boolean (auto-unboxing 2nd operand to boolean)

E2: `true ? null : false` - Boolean (autoboxing of 3rd operand to Boolean)

জাভা ভাষার নির্দিষ্টকরণ, বিভাগ 15.25 শর্তসাপেক্ষ অপারেটরটি দেখুন ? :

  • E1 এর জন্য ২ য় এবং ৩ য় অপারেশনগুলির ধরণ যথাক্রমে Booleanএবং booleanতাই এই ধারাটি প্রযোজ্য:

    যদি দ্বিতীয় এবং তৃতীয় অপারেন্ডগুলির মধ্যে একটি টাইপ বুলিয়ান হয় এবং অন্যটির ধরণের বুলিয়ান টাইপ হয় তবে শর্তসাপেক্ষ প্রকাশের ধরণটি বুলিয়ান।

    যেহেতু প্রকাশের booleanধরণটি, তাই দ্বিতীয় অপারেন্ডকে অবশ্যই জোর করতে হবে boolean। সংকলকটি returnsNull()এটিকে তৈরি করতে 2 য় অপরেন্ডে (ফেরতের মান ) স্বয়ংক্রিয়-আনবক্সিং কোড সন্নিবেশ করায় boolean। এটি অবশ্যই nullরান-টাইমে রিটার্ন থেকে আসা এনপিইর কারণ ঘটায় ।

  • E2- এর জন্য, 2 য় এবং 3 য় অপারেশনগুলির ধরণগুলি যথাক্রমে <special null type>( Booleanই 1 এর মতো নয় !) এবং booleanতাই কোনও নির্দিষ্ট টাইপিং ক্লজ প্রযোজ্য নয় ( এমমে পড়ুন! ), সুতরাং চূড়ান্ত "অন্যথায়" ধারা প্রয়োগ করা হয়:

    অন্যথায়, দ্বিতীয় এবং তৃতীয় অপারেশনগুলি যথাক্রমে এস 1 এবং এস 2 ধরণের। এস 1-তে বক্সিং রূপান্তর প্রয়োগের ফলে টি 1-কে সেই ধরণের ফলাফল দেওয়া হোক এবং এস 2-তে বক্সিং রূপান্তর প্রয়োগের ফলে টি 2 কে এমন ধরণের রূপ দিন। শর্তসাপেক্ষ প্রকাশের প্রকারটি হ'ল ক্যাপচার রূপান্তর (.15.1.10) প্রয়োগ করে (টি 1, টি 2) (.115.12.2.7) .7

    • এস 1 == <special null type>(দেখুন §4.1 )
    • এস 2 == boolean
    • টি 1 == বাক্স (এস 1) == <special null type>( §5.1.7 এ বক্সিং রূপান্তরগুলির তালিকার শেষ আইটেমটি দেখুন )
    • টি 2 == বাক্স (এস 2) == oo বুলিয়ান
    • lub (টি 1, টি 2) == Boolean

    সুতরাং শর্তসাপেক্ষ প্রকাশের Booleanধরণটি এবং তৃতীয় অপারেন্ডকে অবশ্যই জোর করা উচিত Boolean। সংকলক 3 য় অপরেন্ড ( false) এর জন্য অটো-বক্সিং কোড সন্নিবেশ করায় । ২ য় অপরেন্ডের মতো অটো-আনবক্সিংয়ের দরকার নেই E1, সুতরাং nullফিরে আসার সময় কোনও স্বয়ংক্রিয়-আনবক্সিং নেই PE


এই প্রশ্নের একই ধরণের বিশ্লেষণের প্রয়োজন:

জাভা শর্তসাপেক্ষ অপারেটর?: ফলাফলের ধরণ


4
বোধ হয় ... আমি মনে করি। §15.12.2.7 ব্যাথা হয়।
বালুসসি

এটি সহজ ... তবে কেবল অন্ধকারে। :-)
বার্ট এফ

@BertF কি ফাংশন আছে lubযে lub(T1,T2)জন্য স্ট্যান্ড?
গিক 6

1
@ গীক - লুব () - কমপক্ষে উপরের আবদ্ধ - মূলত তাদের নিকটে থাকা নিকটতম সুপারক্লাস; যেহেতু নাল (টাইপ "স্পেশাল নাল টাইপ") যেকোন প্রকারে স্পষ্টত রূপান্তরিত (প্রশস্ত) করা যায়, তাই আপনি বিশেষ নাল টাইপকে লুব () এর উদ্দেশ্যে কোনও প্রকারের (শ্রেণির) "সুপারক্লাস" হিসাবে বিবেচনা করতে পারেন।
বার্ট এফ

25

লাইন:

    Boolean b = true ? returnsNull() : false;

অভ্যন্তরীণভাবে রূপান্তরিত হয়:

    Boolean b = true ? returnsNull().booleanValue() : false; 

আনবক্সিং সম্পাদন করা; সুতরাং: null.booleanValue()একটি এনপাই ফলিত হবে

অটোবক্সিং ব্যবহার করার সময় এটি অন্যতম প্রধান সমস্যা। এই আচরণটি প্রকৃতপক্ষে 5.1.8 জেএলএসে নথিভুক্ত করা হয়েছে

সম্পাদনা: আমি বিশ্বাস করি যে তৃতীয় অপারেটর বুলিয়ান প্রকারের মতো (আনুষঙ্গিক কাস্ট যুক্ত) এর কারণে আনবক্সিংটি হয়েছে:

   Boolean b = (Boolean) true ? true : false; 

2
চূড়ান্ত মান বুলিয়ান অবজেক্ট যখন কেন এটির মতো আনবক্স করার চেষ্টা করে না?
এরিক রবার্টসন

16

থেকে জাভা ল্যাঙ্গুএজ স্পেসিফিকেশন, অধ্যায় 15,25 :

  • যদি দ্বিতীয় এবং তৃতীয় অপারেন্ডগুলির মধ্যে একটি টাইপ বুলিয়ান হয় এবং অন্যটির ধরণের বুলিয়ান টাইপ হয় তবে শর্তসাপেক্ষ প্রকাশের ধরণটি বুলিয়ান।

সুতরাং, প্রথম উদাহরণটি প্রথম নিয়ম অনুসারে Boolean.booleanValue()রূপান্তর Booleanকরতে কল করতে চেষ্টা করে boolean

দ্বিতীয় ক্ষেত্রে প্রথম অপারেন্ডটি নাল টাইপের হয়, যখন দ্বিতীয়টি রেফারেন্স টাইপের নয়, সুতরাং অটোবক্সিং রূপান্তরটি প্রয়োগ করা হয়:

  • অন্যথায়, দ্বিতীয় এবং তৃতীয় অপারেশনগুলি যথাক্রমে এস 1 এবং এস 2 ধরণের। এস 1-তে বক্সিং রূপান্তর প্রয়োগের ফলে টি 1-কে সেই ধরণের ফলাফল দেওয়া হোক এবং এস 2-তে বক্সিং রূপান্তর প্রয়োগের ফলে টি 2 কে এমন ধরণের রূপ দিন। শর্তসাপেক্ষ প্রকাশের প্রকারটি হ'ল ক্যাপচার রূপান্তর (.15.1.10) প্রয়োগ করে (টি 1, টি 2) (.115.12.2.7) .7

এটি প্রথম ক্ষেত্রে উত্তর দেয়, তবে দ্বিতীয় ক্ষেত্রে নয়।
BalusC

সম্ভবত যখন মানগুলির মধ্যে একটি হয় তখন এর ব্যতিক্রম হয় null
এরিক রবার্টসন

@ এরিক: জেএলএস কি এটি নিশ্চিত করে?
বালুসসি

1
@ এরিক: আমি মনে করি না যে এটি প্রযোজ্য কারণ booleanএটি কোনও রেফারেন্স টাইপ নয়।
axtavt

1
এবং আমি যুক্ত করতে পারি ... এজন্য আপনার প্রয়োজন মতো তিনটি পক্ষকে একই ধরণের করা উচিত licit এমনকি যদি আপনার চশমাটি মুখস্থ থাকে এবং কী ঘটে তা জানেন তবে পরবর্তী প্রোগ্রামারটি আপনার কোডটি পড়তে পারে না। আমার নম্র মতামত অনুসারে, সাধারণ মানুষের মৃত্যুর পূর্বাভাস দেওয়া মুশকিল এমন কিছু না করে সংকলক যদি এই পরিস্থিতিতে কেবল ত্রুটি বার্তা প্রকাশ করে তবে ভাল হয় better ওয়েল, সম্ভবত এমন কিছু ঘটনা রয়েছে যেখানে আচরণটি সত্যই কার্যকর, তবে আমি এখনও একটিটিকে আঘাত করি নি।
জয়

0

আমরা এই সমস্যাটি বাইট কোড থেকে দেখতে পারি। মাইনের বাইট কোডের 3 লাইনে 3: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z, বক্সিং বুলিয়ান মান নাল, invokevirtualপদ্ধতি java.lang.Boolean.booleanValue, এটি অবশ্যই এনপিই নিক্ষেপ করবে।

    public static void main(java.lang.String[]) throws java.lang.Exception;
      descriptor: ([Ljava/lang/String;)V
      flags: ACC_PUBLIC, ACC_STATIC
      Code:
        stack=2, locals=2, args_size=1
           0: invokestatic  #2                  // Method returnsNull:()Ljava/lang/Boolean;
           3: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
           6: invokestatic  #4                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
           9: astore_1
          10: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          13: aload_1
          14: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
          17: return
        LineNumberTable:
          line 3: 0
          line 4: 10
          line 5: 17
      Exceptions:
        throws java.lang.Exception

    public static java.lang.Boolean returnsNull();
      descriptor: ()Ljava/lang/Boolean;
      flags: ACC_PUBLIC, ACC_STATIC
      Code:
        stack=1, locals=0, args_size=0
           0: aconst_null
           1: areturn
        LineNumberTable:
          line 8: 0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.