স্ট্যাটিক ইনিশিয়ালাইজেশন ব্লক থেকে জাভা কেন একটি চেক করা ব্যতিক্রম নিক্ষেপ করতে দেয় না? এই ডিজাইনের সিদ্ধান্তের পিছনে কারণ কী ছিল?
স্ট্যাটিক ইনিশিয়ালাইজেশন ব্লক থেকে জাভা কেন একটি চেক করা ব্যতিক্রম নিক্ষেপ করতে দেয় না? এই ডিজাইনের সিদ্ধান্তের পিছনে কারণ কী ছিল?
উত্তর:
কারণ আপনার উত্সে এই চেক করা ব্যতিক্রমগুলি পরিচালনা করা সম্ভব নয়। প্রারম্ভিককরণ প্রক্রিয়াটির উপর আপনার কোনও নিয়ন্ত্রণ নেই এবং আপনার উত্স থেকে স্থির}} ব্লকগুলি কল করা যায় না যাতে চেষ্টা করে আপনি এগুলি ঘিরে রাখতে পারেন।
আপনি কোনও পরীক্ষিত ব্যতিক্রম দ্বারা নির্দেশিত কোনও ত্রুটি পরিচালনা করতে পারবেন না, তাই চেক করা ব্যতিক্রম স্ট্যাটিক ব্লক নিক্ষেপ করার অনুমতি দেওয়া হয়নি।
স্ট্যাটিক ব্লক অবশ্যই চেক করা ব্যতিক্রমগুলি ছুঁড়ে ফেলবে না তবুও চেক করা / রানটাইম-ব্যতিক্রমগুলি ছুঁড়ে ফেলার অনুমতি দেয়। তবে উপরের কারণ অনুসারে আপনি এগুলি পরিচালনা করতেও অক্ষম হবেন।
সংক্ষিপ্তসার হিসাবে, এই বিধিনিষেধটি বিকাশকারীকে এমন কিছু তৈরি করা থেকে বাধা দেয় (যার ফলে ত্রুটি হতে পারে যা থেকে অ্যাপ্লিকেশনটি পুনরুদ্ধার করতে অক্ষম হবে।
static { if(1 < 10) { throw new NullPointerException(); } }
যে কোনও চেক করা ব্যতিক্রম ধরা এবং এটি একটি চেক করা ব্যতিক্রম হিসাবে পুনর্বিবেচনা করে আপনি সমস্যার আশপাশে কাজ করতে পারেন। এই অবারিত ব্যতিক্রম বর্গ একটি লেফাফা পাশাপাশি কাজ করে: java.lang.ExceptionInInitializerError
।
কোডের উদাহরণ:
protected static class _YieldCurveConfigHelperSingleton {
public static YieldCurveConfigHelper _staticInstance;
static {
try {
_staticInstance = new YieldCurveConfigHelper();
}
catch (IOException | SAXException | JAXBException e) {
throw new ExceptionInInitializerError(e);
}
}
}
catch (Exception e) {
পরিবর্তে।
System.exit(...)
(বা সমতুল্য) হ'ল আপনার একমাত্র বিকল্প,
এটি দেখতে এমন হবে (এই হল না বৈধ জাভা কোড)
// Not a valid Java Code
static throws SomeCheckedException {
throw new SomeCheckedException();
}
আপনি যেখানে এটি ধরবেন সেখানে বিজ্ঞাপনটি কীভাবে হবে? চেক করা ব্যতিক্রমগুলি ধরা দরকার। কিছু উদাহরণ কল্পনা করুন যা ক্লাসটি সূচনা করতে পারে (বা এটি ইতিমধ্যে আরম্ভ করা হয়েছে বলেই নাও হতে পারে), এবং এটি যে জটিলতার পরিচয় দেবে তার মনোযোগ আকর্ষণ করার জন্য, আমি উদাহরণগুলিকে অন্য স্ট্যাটিক ইনিটালাইজারে রেখেছি:
static {
try {
ClassA a = new ClassA();
Class<ClassB> clazz = Class.forName(ClassB.class);
String something = ClassC.SOME_STATIC_FIELD;
} catch (Exception oops) {
// anybody knows which type might occur?
}
}
এবং অন্য একটি খারাপ জিনিস -
interface MyInterface {
final static ClassA a = new ClassA();
}
কল্পনা করুন ক্লাসএতে একটি স্ট্যাটিক ইনিশিয়ালাইজার ছিল যাচাই করা ব্যতিক্রম ছুঁড়েছে: এক্ষেত্রে মাইইনটারফেস (যা একটি 'লুকানো' স্ট্যাটিক ইনিশিয়ালাইজারের সাথে একটি ইন্টারফেস) ব্যতিক্রম ছোঁড়াতে বা এটি পরিচালনা করতে হবে - কোনও ইন্টারফেসে ব্যতিক্রম হ্যান্ডলিং? এটি যেমন আছে তেমন ছেড়ে দিন।
main
চেক করা ব্যতিক্রম ছুঁড়ে ফেলতে পারে। স্পষ্টতই সেগুলি পরিচালনা করা যায় না।
main()
যা স্ট্যাক ট্রেস দিয়ে ব্যতিক্রমটি মুদ্রণ করে System.err
, তারপরে কল করে System.exit()
। শেষ পর্যন্ত, এই প্রশ্নের উত্তর সম্ভবত: "কারণ জাভা ডিজাইনাররা তাই বলেছিলেন"।
স্ট্যাটিক ইনিশিয়ালাইজেশন ব্লক থেকে জাভা কেন একটি চেক করা ব্যতিক্রম নিক্ষেপ করতে দেয় না?
প্রযুক্তিগতভাবে, আপনি এটি করতে পারেন। তবে, পরীক্ষিত ব্যতিক্রম অবশ্যই ব্লকের মধ্যে ধরা উচিত be একটি পরীক্ষিত ব্যতিক্রম ব্লক থেকে প্রচার করার অনুমতি নেই ।
প্রযুক্তিগতভাবে, একটি স্ট্যাটিক ইনিশিয়ালাইজার ব্লক 1 এর বাইরে কোনও চেক করা ব্যতিক্রমকেও প্রচার করতে দেওয়া সম্ভব । তবে এটি ইচ্ছাকৃতভাবে করা সত্যিই খারাপ ধারণা! সমস্যাটি হ'ল জেভিএম নিজেই অচিহ্নযুক্ত ব্যতিক্রমটি ধরবে এবং এটিকে জড়িয়ে রাখবে এবং এটিকে আবার নতুন করে দেখায়ExceptionInInitializerError
।
এনবি: এটি একটি Error
একটি নিয়মিত ব্যতিক্রম নয়। আপনার এটি থেকে পুনরুদ্ধার করার চেষ্টা করা উচিত নয়।
বেশিরভাগ ক্ষেত্রে, ব্যতিক্রম ধরা যায় না:
public class Test {
static {
int i = 1;
if (i == 1) {
throw new RuntimeException("Bang!");
}
}
public static void main(String[] args) {
try {
// stuff
} catch (Throwable ex) {
// This won't be executed.
System.out.println("Caught " + ex);
}
}
}
$ java Test
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Bang!
at Test.<clinit>(Test.java:5)
2try ... catch
ধরার জন্য আপনি উপরের কোনও জায়গায় রাখতে পারবেন নাExceptionInInitializerError
।
কিছু ক্ষেত্রে আপনি এটি ধরতে পারেন। উদাহরণস্বরূপ, যদি আপনি কল করে ক্লাস ইনিশিয়েশনটি ট্রিগার করেন Class.forName(...)
, আপনি কলটি একটিতে বন্ধ করে দিতে পারেন এবং একটি বা try
পরবর্তীটি ধরতে পারেনExceptionInInitializerError
NoClassDefFoundError
।
তবে, যদি আপনি কোনওটি থেকে পুনরুদ্ধার করার চেষ্টা করেন তবে আপনি একটি ExceptionInInitializerError
রোড ব্লক দৌড়ে দায়বদ্ধ। সমস্যাটি হ'ল ত্রুটিটি ছুঁড়ে ফেলার আগে, জেভিএম ক্লাস চিহ্নিত করে যা সমস্যাটি "ব্যর্থ" হিসাবে চিহ্নিত করে। আপনি কেবল এটি ব্যবহার করতে সক্ষম হবেন না। তদ্ব্যতীত, ব্যর্থ শ্রেণীর উপর নির্ভরশীল অন্য কোনও শ্রেণি যদি তারা আরম্ভ করার চেষ্টা করে তবে ব্যর্থ অবস্থায়ও যাবে। এগিয়ে যাওয়ার একমাত্র উপায় হ'ল সমস্ত ব্যর্থ ক্লাসকে আনলোড করা। এটি গতিশীল লোড কোড 3 এর জন্য সম্ভব হতে পারে , তবে সাধারণভাবে তা হয় না।
1 - স্থিতিশীল ব্লকটি নিঃশর্তভাবে একটি চেক করা ব্যতিক্রম ছুঁড়ে ফেলা হলে এটি সংকলন ত্রুটি ।
2 - আপনি কোনও পূর্বনির্ধারিত ব্যতিক্রম ব্যতিক্রম হ্যান্ডলারটি রেজিস্ট্রেশন করে এটিকে আটকাতে সক্ষম হতে পারেন তবে এটি আপনাকে পুনরুদ্ধার করতে দেয় না কারণ আপনার "মূল" থ্রেড শুরু হতে পারে না।
3 - আপনি যদি ব্যর্থ ক্লাসগুলি পুনরুদ্ধার করতে চান, আপনার ক্লাসলোডার যে লোড করেছে সেগুলি থেকে আপনাকে মুক্তি দিতে হবে।
এই ডিজাইনের সিদ্ধান্তের পিছনে কারণ কী ছিল?
প্রোগ্রামারকে কোড লেখা থেকে রক্ষা করা যা হ্যান্ডেল করা যায় না এমন ব্যতিক্রম ছুঁড়ে দেয় !
যেমনটি আমরা দেখেছি, স্ট্যাটিক ইনিশিয়ালাইজারের একটি ব্যতিক্রম একটি সাধারণ অ্যাপ্লিকেশনটিকে একটি ইটের মধ্যে পরিণত করে। ভাষা ডিজাইনাররা যেটি করতে পারে তা সবচেয়ে ভাল কথাটি সংকলনের ত্রুটি হিসাবে চেক করা কেসটি মোকাবেলা করা। (দুর্ভাগ্যক্রমে, চেক করা ব্যতিক্রমগুলির জন্য এটি করাও ব্যবহারিক নয় is)
ঠিক আছে, সুতরাং যদি আপনার কোডটি একটি স্ট্যাটিক ইনিশিয়ালাইজারে ব্যতিক্রম ছোঁড়ার "প্রয়োজন" হয় তবে আপনার কী করা উচিত। মূলত, দুটি বিকল্প রয়েছে:
যদি (পূর্ণ!) ব্লকের মধ্যে ব্যতিক্রম থেকে পুনরুদ্ধার সম্ভব হয়, তবে এটি করুন।
অন্যথায়, আপনার কোডটি পুনর্গঠন করুন যাতে কোনও স্ট্যাটিক ইনিশিয়ালাইজেশন ব্লক (বা স্ট্যাটিক ভেরিয়েবলগুলির আরম্ভকারীগুলিতে) সূচনা না ঘটে।
জাভা ল্যাঙ্গুয়েজ স্পেসিফিকেশনগুলির দিকে একবার নজর দিন : এটি স্থিতিশীল আরম্ভকারী ব্যর্থ যদি চেক করা ব্যতিক্রম সহ আকস্মিকভাবে সম্পূর্ণ করতে সক্ষম হয় তবে এটি একটি সংকলন সময় ত্রুটি বলে উল্লেখ করা হয় ।
public class Main { static { try{Class.forName("whathappenswhenastaticblockthrowsanexception");} catch (ClassNotFoundException e){throw new RuntimeException(e);} } public static void main(String[] args){} }
আউটপুট:Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: whathappenswhenastaticblockthrowsanexception at Main.<clinit>(Main.java:6) Caused by: java.lang.ClassNotFoundException: whathappen...
যেহেতু আপনি যে কোনও কোড লিখেছেন তা স্ট্যাটিক ইনিশিয়ালাইজেশন ব্লকে কল করতে পারে না তাই এটি পরীক্ষা করা নিক্ষেপ করা কার্যকর নয় exceptions
। যদি এটি সম্ভব হত, একটি চেক করা ব্যতিক্রম ছুঁড়ে ফেলা হলে jvm কী করবে? Runtimeexceptions
প্রচার করা হয়।
উদাহরণস্বরূপ: স্প্রিংয়ের ডিসপ্যাচারসার্ভালেট (org.springframework.web.servlet.DispatcherServlet) একটি দৃশ্যের ব্যয় করে যা একটি চেক করা ব্যতিক্রম ধরা পড়ে এবং অন্য একটি চেক করা ব্যতিক্রম ছোঁড়ে।
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
আমি একটি চেক করা ব্যতিক্রম ছোঁড়াটিও সংকলন করতে সক্ষম হয়েছি ...
static {
try {
throw new IOException();
} catch (Exception e) {
// Do Something
}
}