জাভা জেনেরিক্স হল জাভা ভাষার অন্যতম গুরুত্বপূর্ণ বৈশিষ্ট্য। জেনেরিকের পিছনের ধারণাটি বেশ সহজ, তবে, এটির সাথে যুক্ত সাধারণ সিনট্যাক্স থেকে সরে যাওয়ার কারণে এটি কখনও কখনও জটিল হয়ে ওঠে।
এই টিউটোরিয়ালের উদ্দেশ্য হল জেনেরিকের এই দরকারী ধারণার সাথে সহজে বোঝার জন্য আপনাকে পরিচয় করিয়ে দেওয়া।
তবে জেনেরিক্সে ডুব দেওয়ার আগে, আসুন জেনে নেওয়া যাক কেন জাভা জেনেরিকের প্রথম প্রয়োজন ছিল।
জাভা জেনেরিকের উদ্দেশ্য
জাভা 5-এ জেনেরিক প্রবর্তনের আগে, আপনি কোনও ত্রুটি বা সতর্কতা ছাড়াই এইরকম একটি কোড স্নিপেট লিখতে এবং কম্পাইল করতে পারেন:
List list = new ArrayList();
list.add("hey");
list.add(new Object());
কোন ধরনের তথ্য সংরক্ষণ করে তা ঘোষণা না করেই আপনি তালিকায় বা অন্য জাভা সংগ্রহে যেকোনো ধরনের মান যোগ করতে পারেন। কিন্তু যখন আপনি তালিকা থেকে মানগুলি পুনরুদ্ধার করবেন, তখন আপনাকে স্পষ্টভাবে এটিকে একটি নির্দিষ্ট ধরনের কাস্ট করতে হবে।
উপরের তালিকার মাধ্যমে পুনরাবৃত্তি করার কথা বিবেচনা করুন।
for (int i=0; i< list.size(); i++) {
String value = (String) list.get(i); //CastClassException when i=1
}
প্রথমে সংরক্ষিত ডেটা টাইপ ঘোষণা না করে একটি তালিকা তৈরি করার অনুমতি দেওয়া, যেমন আমরা করেছি, প্রোগ্রামাররা উপরে যেমন ClassCastExceptions
থ্রো করে ভুল করতে পারে রানটাইম চলাকালীন।
প্রোগ্রামারদের এই ধরনের ভুল করা থেকে বিরত রাখতে জেনেরিক চালু করা হয়েছিল।
জেনেরিকের সাহায্যে, আপনি স্পষ্টভাবে ঘোষণা করতে পারেন যে ডাটা টাইপ যেটি একটি জাভা সংগ্রহ তৈরি করার সময় সংরক্ষণ করা হবে যেমনটি নিম্নলিখিত উদাহরণটি দেখায়৷
দ্রষ্টব্য:আপনি এখনও সঞ্চিত ডেটা টাইপ নির্দিষ্ট না করে একটি জাভা সংগ্রহ বস্তু তৈরি করতে পারেন কিন্তু এটি সুপারিশ করা হয় না।List<String> stringList = new ArrayList<>();
এখন, আপনি একটি কম্পাইল-টাইম ত্রুটি নিক্ষেপ না করে ভুলভাবে একটি স্ট্রিং টাইপ তালিকায় একটি পূর্ণসংখ্যা সংরক্ষণ করতে পারবেন না। এটি নিশ্চিত করে যে আপনার প্রোগ্রামটি রানটাইম ত্রুটির মধ্যে না চলে।
stringList.add(new Integer(4)); //Compile time Error
জাভাতে জেনেরিক প্রবর্তনের মূল উদ্দেশ্য ছিল ClassCastExceptions
এ দৌড়ানো এড়ানো। রানটাইম চলাকালীন।
জাভা জেনেরিক তৈরি করা
আপনি জাভা ক্লাস এবং পদ্ধতি তৈরি করতে জেনেরিক ব্যবহার করতে পারেন। আসুন প্রতিটি ধরণের জেনেরিক তৈরি করার উদাহরণগুলি দেখি।
জেনারিক ক্লাস
একটি জেনেরিক ক্লাস তৈরি করার সময়, ক্লাসের জন্য টাইপ প্যারামিটারটি ক্লাস নামের শেষে কোণ <>
এর মধ্যে যোগ করা হয়। বন্ধনী।
public class GenericClass<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return this.item;
}
}
এখানে, T
ডাটা টাইপ প্যারামিটার। T
, N
, এবং E
জাভা কনভেনশন অনুযায়ী ডেটা টাইপ প্যারামিটারের জন্য ব্যবহৃত কিছু অক্ষর।
উপরের উদাহরণে, আপনি জেনেরিকক্লাস অবজেক্ট তৈরি করার সময় এটিকে একটি নির্দিষ্ট ডেটা টাইপ পাস করতে পারেন।
public static void main(String[] args) {
GenericClass<String> gc1 = new GenericClass<>();
gc1.setItem("hello");
String item1 = gc1.getItem(); // "hello"
gc1.setItem(new Object()); //Error
GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setItem(new Integer(1));
Integer item2 = gc2.getItem(); // 1
gc2.setItem("hello"); //Error
}
একটি জেনেরিক ক্লাস অবজেক্ট তৈরি করার সময় আপনি ডেটা টাইপ প্যারামিটারে একটি আদিম ডেটা টাইপ পাস করতে পারবেন না। অবজেক্ট টাইপ প্রসারিত শুধুমাত্র ডেটা টাইপ টাইপ প্যারামিটার হিসাবে পাস করা যেতে পারে।
যেমন:
GenericClass<float> gc3 = new GenericClass<>(); //Error
জেনারিক পদ্ধতি
জেনেরিক পদ্ধতি তৈরি করা জেনেরিক ক্লাস তৈরির অনুরূপ প্যাটার্ন অনুসরণ করে। আপনি জেনেরিক ক্লাসের পাশাপাশি নন-জেনারিক পদ্ধতিতে একটি জেনেরিক পদ্ধতি প্রয়োগ করতে পারেন।
(int i=0; ipublic class GenericMethodClass {
public static <T> void printItems(T[] arr){
for (int i=0; i< arr.length; i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
String[] arr1 = {"Cat", "Dog", "Mouse"};
Integer[] arr2 = {1, 2, 3};
GenericMethodClass.printItems(arr1); // "Cat", "Dog", "Mouse"
GenericMethodClass.printItems(arr2); // 1, 2, 3
}
}
এখানে, আপনি পদ্ধতিটি প্যারামিটারাইজ করার জন্য একটি নির্দিষ্ট ধরণের একটি অ্যারে পাস করতে পারেন। জেনেরিক পদ্ধতি PrintItems()
পাস করা অ্যারের মাধ্যমে পুনরাবৃত্তি করে এবং একটি সাধারণ জাভা পদ্ধতির মতোই সংরক্ষিত আইটেমগুলিকে প্রিন্ট করে।
বাউন্ডেড টাইপ প্যারামিটার
এখনও অবধি, আমরা উপরে তৈরি করা জেনেরিক ক্লাস এবং পদ্ধতিগুলি আদিম প্রকারগুলি ছাড়া অন্য যে কোনও ডেটা টাইপের সাথে প্যারামিটারাইজ করা যেতে পারে। কিন্তু যদি আমরা জেনেরিকগুলিতে পাস করা যেতে পারে এমন ডেটা প্রকারগুলিকে সীমাবদ্ধ করতে চাই? এখানেই বাউন্ডেড টাইপ প্যারামিটার আসে।
আপনি একটি জেনেরিক ক্লাস বা পদ্ধতি দ্বারা গৃহীত ডেটা প্রকারগুলিকে নির্দিষ্ট করে আবদ্ধ করতে পারেন যে এটি অন্য ডেটা টাইপের একটি সাবক্লাস হওয়া উচিত৷
যেমন:
//accepts only subclasses of List
public class UpperBoundedClass<T extends List>{
//accepts only subclasses of List
public <T extends List> void UpperBoundedMethod(T[] arr) {
}
}
এখানে, UpperBoundedClass
এবং UpperBoundedMethod
শুধুমাত্র List
-এর উপপ্রকার ব্যবহার করে প্যারামিটারাইজ করা যেতে পারে ডেটা টাইপ।
List
ডেটা টাইপ টাইপ প্যারামিটারের উপরের আবদ্ধ হিসাবে কাজ করে। আপনি যদি এমন ডেটা টাইপ ব্যবহার করার চেষ্টা করেন যা List
-এর সাব-টাইপ নয় , এটি একটি কম্পাইল-টাইম ত্রুটি নিক্ষেপ করবে।
সীমাবদ্ধতা শুধুমাত্র ক্লাসে সীমাবদ্ধ নয়। আপনি পাশাপাশি ইন্টারফেস পাস করতে পারেন. ইন্টারফেস প্রসারিত করা মানে, এই ক্ষেত্রে, ইন্টারফেস বাস্তবায়ন করা।
একটি প্যারামিটারের একাধিক সীমাও থাকতে পারে যেমন এই উদাহরণটি দেখায়৷
//accepts only subclasses of both Mammal and Animal
public class MultipleBoundedClass<T extends Mammal & Animal>{
//accepts only subclasses of both Mammal and Animal
public <T extends Mammal & Animal> void MultipleBoundedMethod(T[] arr){
}
}
গ্রহণযোগ্য ডেটা টাইপ অবশ্যই প্রাণী এবং স্তন্যপায়ী উভয় শ্রেণীর একটি উপশ্রেণী হতে হবে। যদি এই সীমাগুলির মধ্যে একটি একটি শ্রেণী হয়, তবে এটি অবশ্যই আবদ্ধ ঘোষণায় প্রথমে আসবে৷
উপরের উদাহরণে, যদি স্তন্যপায়ী একটি শ্রেণী হয় এবং প্রাণী একটি ইন্টারফেস হয়, তাহলে উপরে দেখানো হিসাবে স্তন্যপায়ীকে প্রথমে আসতে হবে। অন্যথায়, কোডটি একটি কম্পাইল-টাইম ত্রুটি নিক্ষেপ করে।
জাভা জেনেরিক ওয়াইল্ডকার্ড
ওয়াইল্ডকার্ডগুলি জেনেরিক ধরণের প্যারামিটারগুলিকে পদ্ধতিতে প্রেরণ করতে ব্যবহৃত হয়। একটি জেনেরিক পদ্ধতির বিপরীতে, এখানে, জেনেরিক প্যারামিটারটি পদ্ধতি দ্বারা গৃহীত পরামিতিগুলিতে প্রেরণ করা হয়, যা আমরা উপরে আলোচনা করা ডেটা টাইপ প্যারামিটার থেকে আলাদা। একটি ওয়াইল্ডকার্ড দ্বারা প্রতিনিধিত্ব করা হয়? প্রতীক।
public void printItems(List<?> list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
}
}
উপরের printItems()
মেথড প্যারামিটার হিসেবে যেকোনো ডাটা টাইপের তালিকা গ্রহণ করে। এটি প্রোগ্রামারদের বিভিন্ন ডেটা প্রকারের তালিকার জন্য কোড পুনরাবৃত্তি করতে বাধা দেয়, যা জেনেরিক ছাড়াই হবে।
উর্ধ্ব বাউন্ডেড ওয়াইল্ডকার্ড
যদি আমরা পদ্ধতি দ্বারা গৃহীত তালিকায় সংরক্ষিত ডেটা প্রকারগুলিকে সীমাবদ্ধ করতে চাই তবে আমরা আবদ্ধ ওয়াইল্ডকার্ড ব্যবহার করতে পারি৷
উদাহরণ:
(int i=0; ipublic void printSubTypes(List<? extends Color> list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
}
}
printSubTypes()
পদ্ধতি শুধুমাত্র তালিকা গ্রহণ করে যা রঙের সাব-টাইপ সংরক্ষণ করে। এটি রেড কালার বা ব্লু কালার বস্তুর একটি তালিকা গ্রহণ করে, কিন্তু প্রাণী বস্তুর একটি তালিকা গ্রহণ করে না। এটি কারণ প্রাণী রঙের একটি উপপ্রকার নয়। এটি একটি উপরের-বাউন্ডেড ওয়াইল্ডকার্ডের একটি উদাহরণ৷
লোয়ার বাউন্ডেড ওয়াইল্ডকার্ড
একইভাবে, যদি আমাদের থাকত:
public void printSuperTypes(List<? super Dog> list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
}
}
তারপর, printSuperTypes()
পদ্ধতি শুধুমাত্র কুকুর শ্রেণীর সুপার ধরনের সঞ্চয় করা তালিকা গ্রহণ করে। এটি স্তন্যপায়ী বা প্রাণী বস্তুর একটি তালিকা গ্রহণ করবে কিন্তু ল্যাবডগ বস্তুর একটি তালিকা নয় কারণ ল্যাবডগ কুকুরের একটি সুপারক্লাস নয়, তবে একটি সাবক্লাস। এটি একটি নিম্ন-সীমাবদ্ধ ওয়াইল্ডকার্ডের একটি উদাহরণ৷
উপসংহার
জাভা জেনেরিক্স এমন একটি বৈশিষ্ট্য হয়ে উঠেছে যা প্রোগ্রামাররা এর প্রবর্তনের পর থেকে ছাড়া বাঁচতে পারে না।
এই জনপ্রিয়তা প্রোগ্রামারদের জীবনকে সহজ করে তোলার উপর প্রভাবের কারণে। কোডিং ভুল করা থেকে তাদের প্রতিরোধ করা ছাড়াও, জেনেরিকের ব্যবহার কোডটিকে কম পুনরাবৃত্তিমূলক করে তোলে। আপনি কি লক্ষ্য করেছেন যে এটি বিভিন্ন ডেটা প্রকারের জন্য কোডের পুনরাবৃত্তি এড়াতে কীভাবে ক্লাস এবং পদ্ধতিগুলিকে সাধারণীকরণ করে?
ভাষাতে বিশেষজ্ঞ হওয়ার জন্য জেনেরিকের ভাল ধারণা থাকা গুরুত্বপূর্ণ। সুতরাং, আপনি এই টিউটোরিয়ালে যা শিখেছেন তা ব্যবহারিক কোডে প্রয়োগ করাই এখন এগিয়ে যাওয়ার উপায়।