অবশেষে ব্লকটিতে ফিরে আসা ভেরিয়েবল পরিবর্তন করা কেন ফেরতের মান পরিবর্তন করে না?


146

নীচে প্রদর্শিত হিসাবে আমার একটি সাধারণ জাভা ক্লাস রয়েছে:

public class Test {

    private String s;

    public String foo() {
        try {
            s = "dev";
            return s;
        } 
        finally {
            s = "override variable s";
            System.out.println("Entry in finally Block");  
        }
    }

    public static void main(String[] xyz) {
        Test obj = new Test();
        System.out.println(obj.foo());
    }
}

এবং এই কোডের আউটপুটটি হ'ল:

Entry in finally Block
dev  

কেন ব্লকটিতে sওভাররাইড করা হয় না finally, তবুও মুদ্রিত আউটপুট নিয়ন্ত্রণ করা হয়?


11
আপনার রিটার্নের স্টেটমেন্টটি শেষ অবধি আটকে দেওয়া উচিত, আমার সাথে পুনরাবৃত্তি করুন, অবশেষে ব্লকটি সর্বদা কার্যকর করা হয়
জুয়ান আন্তোনিও গোমেজ মরিয়ানো


6
বিবৃতি ক্রম গুরুত্বপূর্ণ। আপনি sএর মান পরিবর্তন করার আগে আপনি ফিরছেন ।
পিটার লরি

6
কিন্তু, আপনি করতে পারেন নতুন মান finallyব্লক C #, অসদৃশ (যা তুমি পারবে না)
আলভিন ওং

উত্তর:


167

tryসঞ্চালনের ব্লক সম্পন্ন হয়ে returnবিবৃতি এবং এর মান sসময়ে returnবিবৃতি executes পদ্ধতি দ্বারা ফিরে মান। এই finallyধারাটি পরবর্তীকালে s( returnবিবৃতি সম্পূর্ণ হওয়ার পরে ) এর মান পরিবর্তন করে (এই মুহুর্তে) ফেরতের মান পরিবর্তন করে না।

নোট করুন যে উপরেরগুলি ব্লকটিতে sনিজের মানের পরিবর্তনের সাথে সম্পর্কিত হয় finally, যা sউল্লেখ করা বস্তুর সাথে নয় । যদি sকোনও পরিবর্তনীয় অবজেক্টের संदर्भ হয় (যা Stringনয়) এবং অবজেক্টের বিষয়বস্তুগুলিfinally ব্লকটিতে পরিবর্তন করা হয়েছিল , তবে সেই পরিবর্তনগুলি প্রত্যাবর্তিত মানটিতে দেখা যাবে।

এই সমস্ত কীভাবে পরিচালিত হয় তার বিশদ বিধিগুলি জাভা ভাষা নির্দিষ্টকরণের বিভাগ 14.20.2 এ পাওয়া যাবে । নোট করুন যে একটি returnবিবৃতি কার্যকর করার ফলে tryব্লকটির আকস্মিক সমাপ্তি হিসাবে গণনা করা হয়েছে (" যদি চেষ্টা ব্লকের বাস্তবায়ন হঠাৎ অন্য কোনও কারণে আর .... " প্রযোজ্য হয় তবে শুরু হওয়া বিভাগটি শুরু হয় )। জেএলএসের 14.17 ধারা দেখুন কেন returnবিবৃতিটি কোনও ব্লকের হঠাৎ সমাপ্তি।

আরও বিশদের মাধ্যমে: যদি বিবৃতিটির কারণে কোনও বিবৃতি tryএবং ব্লক উভয়ই হঠাৎ করে বন্ধ হয়ে যায় , তবে §14.20.2 থেকে নিম্নলিখিত বিধিগুলি প্রয়োগ করা হবে:finallytry-finallyreturn

tryঅন্য কোনও কারণে আর [যদি একটি ব্যতিক্রম ছোঁড়ার পাশাপাশি] হঠাৎ করে ব্লকের সম্পাদন সম্পূর্ণ হয়, তবে finallyব্লকটি কার্যকর করা হয় এবং তারপরে একটি বিকল্প রয়েছে:

  • যদি finallyব্লকটি স্বাভাবিকভাবে সম্পূর্ণ হয়, তবে tryবিবৃতিটি হঠাৎ করে আর এর কারণে পূর্ণ হয়।
  • যদি finallyএস কারণে কারণে ব্লকটি হঠাৎ করে সম্পূর্ণ হয়, তবে tryস্টেটমেন্টটি হঠাৎ করে এস কারণে (এবং কারণ আর বাদ দেওয়া হয়) জন্য সম্পূর্ণ হয়।

ফলাফলের যে returnবিবৃতি finallyব্লক সমগ্র ফেরত মান নির্ধারণ করে try-finallyবিবৃতি, এবং থেকে প্রত্যাগত মান tryব্লক বাতিল করা হয়। অনুরূপ একটি জিনিস ঘটে try-catch-finallyযদি বিবৃতি tryব্লক একটি ব্যতিক্রম, এটি একটি দ্বারা ধরা ছোঁড়ার catchব্লক, এবং উভয় catchব্লক এবং finallyব্লক আছে returnবিবৃতি।


আমি যদি স্ট্রিংয়ের পরিবর্তে স্ট্রিংবিল্ডার ক্লাস ব্যবহার করি তবে অবশেষে ব্লকের কিছু মান সংযোজন না করে, তার বদলের মান পরিবর্তন হয়? কেন?
দেবেন্দ্র

6
@ দেব - আমি আমার উত্তরের দ্বিতীয় অনুচ্ছেদে এটি আলোচনা করেছি discuss আপনি যে পরিস্থিতিতে বর্ণনা করেছেন তাতে finallyব্লকটি কোন বস্তুটি (কী StringBuilder) ফিরে আসে তা পরিবর্তন করে না তবে এটি বস্তুর অভ্যন্তরীণ পরিবর্তন করতে পারে। finallyপদ্ধতি সামনে ব্লক, executes আসলে আয় (যদিও returnআগে কলিং কোড ফিরে মান সূচিত বিবৃতি সমাপ্ত হয়েছে), তাই যারা পরিবর্তন ঘটবে।
টেড হপ্প

তালিকা দিয়ে চেষ্টা করুন, আপনি স্ট্রিংবিল্ডারের মতো আচরণ পাবেন।
যোগেশ প্রজাপতি

1
@yogeshprajapati - হ্যাঁ একই কোনো চপল ফেরত মান সঙ্গে সত্য ( StringBuilder, List, Set, বিজ্ঞাপন nauseum): যদি আপনি বিষয়বস্তু পরিবর্তন finallyব্লক, তারপর যারা পরিবর্তন কলিং কোড যখন পদ্ধতি পরিশেষে প্রস্থানের দেখা যায়।
টেড হপ

এটি কী ঘটে তা বলে, এটি কেন বলবে না (এটি যদি জেএলএসে আচ্ছাদিত ছিল তবে এটি নির্দিষ্টভাবে কার্যকর হবে)।
টিজে ক্রাউডার

65

কারণ শেষ অবধি কল করার আগে রিটার্ন মান স্ট্যাকের উপরে রাখা হয়।


3
এটি সত্য, তবে কেন এটি ফিরে আসে তার স্ট্রিংটি পরিবর্তিত হয়নি তা ওপি-র প্রশ্নকে উদ্দেশ্য করে না। স্ট্রাকের রিটার্ন মানকে চাপ দেওয়ার চেয়ে স্ট্রিং অপরিবর্তনীয়তা এবং রেফারেন্স বনাম অবজেক্টের সাথে এটি করতে হবে।
টেম্পলেটটিফাইফ

উভয় ইস্যু সম্পর্কিত।
Tordek

2
@templatetypedef এমনকি স্ট্রিং পরিবর্তনযোগ্য হলেও ব্যবহার করে =তা পরিবর্তন করতে পারে না।
ওয়ান

1
@ সোল - ওভেনের বক্তব্য (যা সঠিক) তা হ'ল ওপি'র finallyব্লকটি কেন ফেরতের মানকে প্রভাবিত করল না তার সাথে অপরিবর্তনীয়তার কোনও যোগসূত্র নেই । আমি মনে করি যে টেম্পলেট টাইপফাইফটি যা পেয়েছিল তা সম্ভবত (যদিও এটি পরিষ্কার নয়) এটি হ'ল কারণ প্রত্যাবর্তিত মান একটি অপরিবর্তনীয় অবজেক্টের একটি রেফারেন্স, এমনকি finallyব্লকের কোড পরিবর্তন করা (অন্য returnবিবৃতি ব্যবহার করা ব্যতীত ) প্রভাব ফেলতে পারে না মানটি পদ্ধতি থেকে ফিরে এসেছে।
টেড হপ

1
পছন্দ করুন স্ট্রিং স্থিতিশীলতার সাথে কিছুই করার নেই। অন্য যে কোনও ধরণের ক্ষেত্রে একই ঘটবে। শেষ অবধি প্রবেশের পূর্বে এটি রিটার্ন-এক্সপ্রেশনকে মূল্যায়নের সাথে করতে হয়, অন্য কথায় সচ্ছলভাবে 'স্ট্যাকের উপর রিটার্ন মানটি চাপানো'।
মার্কুইস

32

যদি আমরা বাইকোডের ভিতরে নজর রাখি তবে আমরা খেয়াল করব যে জেডিকে একটি গুরুত্বপূর্ণ অপ্টিমাইজেশন করেছে এবং ফু () পদ্ধতিটি দেখে মনে হচ্ছে:

String tmp = null;
try {
    s = "dev"
    tmp = s;
    s = "override variable s";
    return tmp;
} catch (RuntimeException e){
    s = "override variable s";
    throw e;
}

এবং বাইটকোড:

0:  ldc #7;         //loading String "dev"
2:  putstatic   #8; //storing it to a static variable
5:  getstatic   #8; //loading "dev" from a static variable
8:  astore_0        //storing "dev" to a temp variable
9:  ldc #9;         //loading String "override variable s"
11: putstatic   #8; //setting a static variable
14: aload_0         //loading a temp avariable
15: areturn         //returning it
16: astore_1
17: ldc #9;         //loading String "override variable s"
19: putstatic   #8; //setting a static variable
22: aload_1
23: athrow

জাভা "দেব" স্ট্রিংটি ফেরার আগে পরিবর্তন করা থেকে রক্ষা করে। আসলে এখানে কোন শেষ অবধি নেই।


এটি কোনও অপ্টিমাইজেশন নয়। এটি কেবল প্রয়োজনীয় শব্দার্থবিজ্ঞানের একটি বাস্তবায়ন উপাদান।
মার্কুইস

22

এখানে 2 টি জিনিস লক্ষণীয়:

  • স্ট্রিংগুলি অপরিবর্তনীয়। আপনি যখন "ওভাররাইড ভেরিয়েবল গুলি" তে সেট করেন, আপনি এসকে ইনলাইনড স্ট্রিংকে উল্লেখ করতে সেট করুন, s এর বস্তুর অন্তর্নিহিত চর বাফারকে "ওভাররাইড ভেরিয়েবল এস" এ পরিবর্তন করতে পরিবর্তন করবেন না।
  • কলিং কোডটিতে ফিরে আসার জন্য আপনি স্ট্যাকের উপর একটি রেফারেন্স রেখেছিলেন। এর পরে (যখন অবশেষে ব্লকটি চলবে), রেফারেন্স পরিবর্তন করে স্ট্যাকের ইতিমধ্যে রিটার্ন মানটির জন্য কিছু করা উচিত নয়।

1
সুতরাং আমি স্ট্রিংবাফার নিলে স্টিং ওভাররাইড হয়ে যাবে ??
দেবেন্দ্র

10
@ দেব - আপনি যদি দফায় বাফারের বিষয়বস্তু পরিবর্তন finallyকরতে চান তবে তা কলিং কোডে দেখা যাবে। তবে, আপনি যদি নতুন স্ট্রিংবফার বরাদ্দ করেন sতবে আচরণটি এখনকার মতোই হবে।
টেড হপ্প

হ্যাঁ যদি আমি স্ট্রিং বাফারে সংযোজন করি তবে অবশেষে ব্লক পরিবর্তনগুলি আউটপুটকে প্রতিফলিত করে।
দেবেন্দ্র

@ 0xCafebabE আপনি খুব ভাল উত্তর এবং ধারণাটিও দেন, আমি আপনাকে আন্তরিক ধন্যবাদ জানাই।
দেবেন্দ্র

13

টেডের পয়েন্টটি প্রমাণ করতে আমি আপনার কোডটি কিছুটা পরিবর্তন করেছি।

আপনি দেখতে পারেন যে আউটপুট sপ্রকৃতপক্ষে পরিবর্তন হয়েছে কিন্তু ফিরে পরে।

public class Test {

public String s;

public String foo() {

    try {
        s = "dev";
        return s;
    } finally {
        s = "override variable s";
        System.out.println("Entry in finally Block");

    }
}

public static void main(String[] xyz) {
    Test obj = new Test();
    System.out.println(obj.foo());
    System.out.println(obj.s);
}
}

আউটপুট:

Entry in finally Block 
dev 
override variable s

ওভাররাইড করা স্ট্রিংগুলি কেন ফিরে আসে না।
দেবেন্দ্র

2
টেড এবং টর্ডেক যেমন ইতিমধ্যে বলেছিলেন যে "শেষ অবধি কার্যকর হওয়ার আগে ফিরতি মানটি স্ট্যাকের উপরে রাখা হয়"
ফ্র্যাঙ্ক

1
যদিও এটি অতিরিক্ত অতিরিক্ত তথ্য, তবে আমি এটিকে উজ্জীবিত করতে নারাজ, কারণ এটি (নিজেরাই) প্রশ্নের উত্তর দেয় না।
জোচিম সৌর

5

প্রযুক্তিগতভাবে বলতে গেলে, ব্লকটিকে সংজ্ঞায়িত returnকরা হলে চেষ্টা ব্লকটি এড়ানো হবে না finally, কেবলমাত্র যদি শেষ অবধি এটিতে একটি অন্তর্ভুক্ত থাকে return

এটি একটি সন্দেহজনক ডিজাইনের সিদ্ধান্ত যা সম্ভবত পূর্ববর্তী ক্ষেত্রে ভুল ছিল (অনেকটা রেফারেন্স যেমন পূর্বনির্ধারিতভাবে অযোগ্য / পরিবর্তনযোগ্য, এবং কিছু মতে, চেক করা ব্যতিক্রম)। অনেক দিক থেকে এই আচরণটি finallyযার অর্থ বলতে বোঝায় তার সাথে সামঞ্জস্যপূর্ণ - " tryব্লকের আগে যা ঘটেছিল তা নয় , সর্বদা এই কোডটি চালান" " সুতরাং আপনি যদি কোনও finallyব্লক থেকে সত্য ফিরে পান , সামগ্রিক প্রভাবটি সর্বদা হওয়া উচিত return s, না?

সাধারণভাবে, এটি খুব কমই একটি ভাল মূর্খতা, এবং আপনার finallyসংস্থানগুলি পরিষ্কার / বন্ধ করার জন্য ব্লকগুলি উদারভাবে ব্যবহার করা উচিত তবে খুব কমই যদি সেগুলি থেকে কোনও মান ফিরে আসে।


এটা সন্দেহজনক কেন? এটি অন্যান্য সমস্ত প্রসঙ্গে মূল্যায়নের আদেশের সাথে একমত।
মারকুইস

0

এটি চেষ্টা করুন: আপনি যদি ওভাররাইড মানটি মুদ্রণ করতে চান।

finally {
    s = "override variable s";    
    System.out.println("Entry in finally Block");
    return s;
}

1
এটি সতর্কতা দেয় .. অবশেষে ব্লকটি সাধারণত সম্পূর্ণ হয় না
দেবেন্দ্র
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.