কেন জাভা থ্রোয়েবলের জেনেরিক সাবক্লাসটিকে অনুমতি দেয় না?


146

জাভা ভাষা বিভাজন অনুসারে , তৃতীয় সংস্করণ:

এটি একটি সংকলন-সময় ত্রুটি যদি জেনেরিক শ্রেণি প্রত্যক্ষ বা অপ্রত্যক্ষ সাবক্লাস হয় Throwable

আমি কেন এই সিদ্ধান্ত নেওয়া হয়েছে তা বুঝতে ইচ্ছুক। জেনেরিক ব্যতিক্রমগুলির সাথে কী সমস্যা?

(যতদূর আমি জানি, জেনেরিকগুলি কেবল সংকলন-সময় সিনট্যাকটিক চিনি, এবং সেগুলিকে যে Objectকোনও উপায়ে .classফাইলগুলিতে অনুবাদ করা হবে , তাই জেনেরিক শ্রেণিকে কার্যকরভাবে ঘোষণা করা যেমন এর সমস্ত কিছু ছিল Objectতবে দয়া করে আমাকে সংশোধন করুন আমি ভুল হলে ।)


1
জেনেরিক ধরণের আর্গুমেন্টগুলি উপরের বাউন্ড দ্বারা প্রতিস্থাপিত হয়, যা ডিফল্টরূপে অবজেক্ট হয়। আপনার কাছে যদি << তালিকার মতো কিছু থাকে? A> প্রসারিত করে, তারপরে A শ্রেণীর ফাইলগুলিতে ব্যবহৃত হয়।
টর্স্টেন মেরেক

ধন্যবাদ @ টারস্টেন আমি আগে এই মামলা সম্পর্কে ভাবেনি।
হোসাম অলি

2
এটি একটি ভাল সাক্ষাত্কারের প্রশ্ন, এটি একটি।
স্ক্যাফম্যান

@ টর্স্টেনমারেক: যদি কেউ কল করে myList.get(i), সম্ভবত getএখনও একটি ফেরত দেয় ObjectAসংকলকটি রানটাইমে কিছু সীমাবদ্ধতা ক্যাপচার করার জন্য একটি কাস্ট inোকান? যদি তা না হয় তবে ওপি ঠিক আছে যে শেষ পর্যন্ত এটি Objectরানটাইমের সময় নেমে যায় । (ক্লাস ফাইলটিতে অবশ্যই মেটাডেটা রয়েছে Aতবে এটি কেবল মেটাডেটা আফাইক))
মিহাই ড্যানিলা

উত্তর:


155

চিহ্ন হিসাবে বলেছে, প্রকারগুলি পুনরায় সংশোধনযোগ্য নয়, যা নিম্নলিখিত ক্ষেত্রে একটি সমস্যা:

try {
   doSomeStuff();
} catch (SomeException<Integer> e) {
   // ignore that
} catch (SomeException<String> e) {
   crashAndBurn()
}

উভয়ই SomeException<Integer>এবং SomeException<String>একই ধরণের মুছে ফেলা হয়, জেভিএমের ব্যতিক্রমের উদাহরণগুলির মধ্যে পার্থক্য করার কোনও উপায় নেই এবং অতএব কোন catchব্লকটি কার্যকর করা উচিত তা বলার উপায় নেই ।


3
তবে "পুনরায় সংশোধনযোগ্য" এর অর্থ কী?
aberrant80

61
সুতরাং নিয়মটি "জেনেরিক প্রকারগুলি সাবক্লাস থ্রোয়েবল হতে পারে না" হওয়া উচিত নয় তবে পরিবর্তে "ক্যাচ ক্লজগুলি সর্বদা কাঁচা প্রকারের ব্যবহার করা উচিত"।
আর্চি

3
তারা কেবল একই ধরণের দুটি ক্যাচ ব্লক একসাথে ব্যবহার করতে পারত না। সুতরাং একা সামেক্সেক্স <Integer> ব্যবহার করা বৈধ হবে, কেবল সামারেক্সেক্স <ইন্টিজার> এবং সামারেক্সেক্স <স্ট্রিং> একসাথে ব্যবহার করা অবৈধ। এতে কোনও সমস্যা হবে না, নাকি?
উইলিয়াম বার

3
ওহ, এখন আমি এটি পেয়েছি। আমার সমাধান রানটাইম এক্সেপশনগুলির সাথে সমস্যার সৃষ্টি করবে, যা ঘোষণা করার দরকার নেই। সুতরাং যদি স্যামেক্সেক্স রানটাইম এক্সেপশনটির একটি সাবক্লাস হয় তবে আমি স্পষ্টভাবে সামারএক্সসি <ইন্টিজার> ফেলতে এবং ধরতে পারি তবে অন্য কোনও ফাংশনটি নিঃশব্দে সামার এক্সেক্স <স্ট্রিং> নিক্ষেপ করছে এবং স্যামেক্সেক্স <ইন্টেজার> এর জন্য আমার ক্যাচ ব্লকটি দুর্ঘটনাক্রমে এটিও ধরতে পারে।
উইলিয়াম বার

4
@ সুপারজেডি ২২৪ - না। এটি তাদের ঠিক করে দেয় - জেনারিকদের পিছনের দিকে সামঞ্জস্যপূর্ণ হতে বাধ্য হওয়া সীমাবদ্ধতার কারণে
স্টিফেন সি

14

ব্যতিক্রমটি কীভাবে ব্যবহার করবেন তার একটি সাধারণ উদাহরণ এখানে:

class IntegerExceptionTest {
  public static void main(String[] args) {
    try {
      throw new IntegerException(42);
    } catch (IntegerException e) {
      assert e.getValue() == 42;
    }
  }
}

ট্রাই স্টেটমেন্টের বডি একটি নির্দিষ্ট মান দিয়ে ব্যতিক্রম ছুঁড়ে দেয়, যা ক্যাচ ক্লজ দ্বারা ধরা পড়ে।

বিপরীতে, একটি নতুন ব্যতিক্রমের নিম্নলিখিত সংজ্ঞাটি নিষিদ্ধ, কারণ এটি একটি প্যারামিটারাইজড টাইপ তৈরি করে:

class ParametricException<T> extends Exception {  // compile-time error
  private final T value;
  public ParametricException(T value) { this.value = value; }
  public T getValue() { return value; }
}

উপরোক্ত সংকলনের একটি প্রচেষ্টা একটি ত্রুটিটি রিপোর্ট করেছে:

% javac ParametricException.java
ParametricException.java:1: a generic class may not extend
java.lang.Throwable
class ParametricException<T> extends Exception {  // compile-time error
                                     ^
1 error

এই সীমাবদ্ধতা বোধগম্য কারণ এ জাতীয় ব্যতিক্রম ধরার প্রায় কোনও প্রচেষ্টা ব্যর্থ হতে হবে, কারণ প্রকারটি পুনরায় সংশোধনযোগ্য নয়। ব্যতিক্রমগুলির একটি সাধারণ ব্যবহার নিম্নলিখিতগুলির মতো হতে পারে বলে আশা করা যায়:

class ParametricExceptionTest {
  public static void main(String[] args) {
    try {
      throw new ParametricException<Integer>(42);
    } catch (ParametricException<Integer> e) {  // compile-time error
      assert e.getValue()==42;
    }
  }
}

এটি অনুমোদিত নয়, কারণ ক্যাচ ক্লজে টাইপটি পুনরায় সংশোধনযোগ্য নয়। এই লেখার সময়, সূর্যের সংকলক এমন ক্ষেত্রে সিনট্যাক্স ত্রুটির একটি ক্যাসকেড রিপোর্ট করে:

% javac ParametricExceptionTest.java
ParametricExceptionTest.java:5: <identifier> expected
    } catch (ParametricException<Integer> e) {
                                ^
ParametricExceptionTest.java:8: ')' expected
  }
  ^
ParametricExceptionTest.java:9: '}' expected
}
 ^
3 errors

যেহেতু ব্যতিক্রমগুলি প্যারাম্যাট্রিক হতে পারে না, সিনট্যাক্সটি সীমিত করা হয় যাতে টাইপটি সনাক্তকারী হিসাবে লিখতে হবে, নিম্নলিখিত প্যারামিটার ছাড়াই।


2
আপনি যখন 'পুনরায় সংশোধনযোগ্য' বলবেন তখন আপনার অর্থ কী? 'পুনরুদ্ধারযোগ্য' কোনও শব্দ নয়।
ফর ইয়োরআউনগুড

1
আমি নিজেই শব্দটি জানতাম না, তবে গুগলে একটি তাত্ক্ষণিক অনুসন্ধানে এটি আমার কাছে পেয়েছিল: java.sun.com/docs/books/jls/third_edition/html/…
হোসাম অলি


13

এটি মূলত কারণ এটি একটি খারাপ পদ্ধতিতে ডিজাইন করা হয়েছিল।

এই সমস্যাটি পরিষ্কার বিমূর্ত নকশাকে প্রতিরোধ করে যেমন,

public interface Repository<ID, E extends Entity<ID>> {

    E getById(ID id) throws EntityNotFoundException<E, ID>;
}

জেনেরিকদের জন্য একটি ক্যাচ ক্লজ ব্যর্থ হবে তা সত্যায়িত করা হয়নি যে এটির জন্য কোনও অজুহাত নয়। সংকলকটি কেবল কংক্রিট জেনেরিক প্রকারগুলিকে অস্বীকার করতে পারে যা ক্যাচ ক্লজের অভ্যন্তরে জেনেরিকগুলিকে প্রসারিত করতে বা জেনারিকগুলি অস্বীকার করতে পারে।


+1 টি। আমার উত্তর - stackoverflow.com/questions/30759692/...
ZhongYu

1
একমাত্র উপায় যে তারা এটি আরও ভালভাবে ডিজাইন করতে পারত তা ছিল গ্রাহকদের কোডের সাথে অসম্পূর্ণ of 10 বছরের রেন্ডারিং। এটি ছিল একটি কার্যকর ব্যবসায়ের সিদ্ধান্ত। নকশাটি সঠিক ছিল ... প্রসঙ্গে
স্টিফেন সি

1
তাহলে কীভাবে আপনি এই ব্যতিক্রমটি ধরবেন? একমাত্র উপায় যে কাজ করবে তা হ'ল কাঁচা টাইপ ধরা EntityNotFoundException। তবে এতে জেনেরিকগুলি অকেজো হয়ে যায়।
ফ্রান্সে

4

জেনেরিকগুলি টাইপ-নির্ভুলতার জন্য সংকলন-সময়ে পরীক্ষা করা হয়। জেনেরিক প্রকারের তথ্যগুলি টাইপ ইরেজোর প্রক্রিয়ায় সরিয়ে ফেলা হয় । উদাহরণস্বরূপ, List<Integer>অ-জেনেরিক প্রকারে রূপান্তরিত হবে List

টাইপ ইরেজরের কারণে , টাইপ পরামিতিগুলি রান-টাইমে নির্ধারণ করা যায় না।

ধরে নেওয়া যাক আপনাকে এরকমভাবে বাড়ানোর অনুমতি দেওয়া হয়েছে Throwable:

public class GenericException<T> extends Throwable

এখন নিম্নলিখিত কোড বিবেচনা করুন:

try {
    throw new GenericException<Integer>();
}
catch(GenericException<Integer> e) {
    System.err.println("Integer");
}
catch(GenericException<String> e) {
    System.err.println("String");
}

টাইপ ইরেজরের কারণে , রানটাইমটি কোন ক্যাচ ব্লকটি সম্পাদন করবে তা জানতে পারবে না।

সুতরাং জেনেরিক ক্লাস থ্রোয়েবলের প্রত্যক্ষ বা অপ্রত্যক্ষ সাবক্লাস হলে এটি একটি সংকলন-সময় ত্রুটি।

উত্স: প্রকার মুছে ফেলার সমস্যা


ধন্যবাদ। এটি টরস্টেনের দেওয়া জবাব হিসাবে একই উত্তর ।
হোসাম অলি

না এইটা না. টর্স্টেনের উত্তরটি আমাকে সাহায্য করে নি, কারণ এটি মুছে ফেলা / পুনর্বিবেচনা কী প্রকার তা ব্যাখ্যা করে না।
গুড নাইট নার্ড অহংকার

2

আমি প্রত্যাশা করব এটি কারণ কারণ পরামিতি গ্যারান্টি কোন উপায় নেই। নিম্নলিখিত কোড বিবেচনা করুন:

try
{
    doSomethingThatCanThrow();
}
catch (MyException<Foo> e)
{
    // handle it
}

আপনি যেমন লক্ষ্য করেছেন, প্যারামিটারাইজেশন হ'ল কেবল সিনট্যাকটিক চিনি। যাইহোক, সংকলকটি এই বিষয়টি নিশ্চিত করার চেষ্টা করে যে সংকলনের সুযোগে কোনও বস্তুর সমস্ত পরামিতিগুলিতে প্যারামিটারাইজেশন সুসংগত থাকে। একটি ব্যতিক্রমের ক্ষেত্রে, সংকলকটির গ্যারান্টি দেওয়ার কোনও উপায় নেই যে মাইএক্সেপশন কেবল প্রক্রিয়াধীন এমন একটি সুযোগ থেকে নিক্ষিপ্ত।


হ্যাঁ, তবে কেন এটি "অনিরাপদ" হিসাবে চিহ্নিত করা হয়নি, উদাহরণস্বরূপ ক্যাসেটগুলির মতো?
এলজেঞ্জো 19

কারণ একটি কাস্টের সাহায্যে আপনি সংকলকটি বলছেন "আমি জানি যে এই কার্যকরকরণের পথটি প্রত্যাশিত ফলাফল উত্পন্ন করে।" ব্যতিক্রম সহ, আপনি বলতে পারবেন না (সমস্ত সম্ভাব্য ব্যতিক্রমের জন্য) "আমি জানি এটি কোথায় ছুঁড়েছিল" " তবে, আমি উপরে যেমন বলেছি এটি অনুমান; আমি সেখানে ছিলাম না।
কেডিগ্রিগরি

"আমি জানি যে এই মৃত্যুদন্ড কার্যকর করার ফলে প্রত্যাশিত ফলাফল পাওয়া যায়।" আপনি জানেন না, আপনি আশা করি। এজন্য জেনেরিক এবং ডাউনকাস্টগুলি স্থিতিশীলভাবে অনিরাপদ তবে তবুও তাদের অনুমতি দেওয়া হয়েছে। আমি টর্স্টেনের উত্তরটিকে অগ্রাহ্য করেছি, কারণ সেখানে আমি সমস্যাটি দেখছি। এখানে আমি না।
এলজেনসো

যদি আপনি না জানেন যে কোনও অবজেক্ট নির্দিষ্ট ধরণের, তবে আপনাকে এটি ingালাই করা উচিত নয়। একটি কাস্টের পুরো ধারণাটি হ'ল সংকলকের চেয়ে আপনার আরও জ্ঞান রয়েছে এবং সেই জ্ঞানটি স্পষ্টভাবে কোডের অংশ হিসাবে তৈরি করছেন।
কেডিগ্রিগরি

হ্যাঁ, এবং এখানে আপনারও কমপাইলারের চেয়ে বেশি জ্ঞান থাকতে পারে, যেহেতু আপনি মাই এক্সেপশন থেকে মাই এক্সসেপশন <ফু> এ একটি চেক না করে রূপান্তর করতে চান। হতে পারে আপনি "জানেন" এটি একটি MyException <Foo> হবে।
এলজেঞ্জো 22
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.