CodeGym /Java Blog /এলোমেলো /জেনেরিকের সাথে কাজ করার সময় varargs ব্যবহার করা
John Squirrels
লেভেল 41
San Francisco

জেনেরিকের সাথে কাজ করার সময় varargs ব্যবহার করা

এলোমেলো দলে প্রকাশিত
ওহে! আজকের পাঠে, আমরা জেনেরিক অধ্যয়ন চালিয়ে যাব। যেহেতু এটি ঘটছে, এটি একটি বড় বিষয়, তবে এটিকে এড়ানোর কিছু নেই — এটি ভাষার একটি অত্যন্ত গুরুত্বপূর্ণ অংশ :) আপনি যখন জেনেরিকের উপর ওরাকল ডকুমেন্টেশন অধ্যয়ন করবেন বা অনলাইন টিউটোরিয়াল পড়বেন, তখন আপনি অ-পুনঃযোগ্য প্রকারের শর্তাবলী দেখতে পাবেন এবং পুনর্বিন্যাসযোগ্য প্রকার । রিফাইয়েবল টাইপ হল এমন একটি টাইপ যার জন্য তথ্য রানটাইমে সম্পূর্ণভাবে পাওয়া যায়। জাভাতে, এই ধরনের প্রকারের মধ্যে রয়েছে আদিম, কাঁচা প্রকার এবং অ-জেনারিক প্রকার। বিপরীতে, নন-রিফাইবল টাইপগুলি হল এমন ধরনের যেগুলির তথ্য মুছে ফেলা হয় এবং রানটাইমে অ্যাক্সেসযোগ্য হয়ে যায়। এটি যেমন ঘটে, এগুলি জেনেরিক — List<String>, List<Integer>ইত্যাদি।

উপায় দ্বারা, আপনি varargs কি মনে আছে?

যদি আপনি ভুলে গেছেন, এটি একটি পরিবর্তনশীল-দৈর্ঘ্যের যুক্তি। তারা এমন পরিস্থিতিতে দরকারী যেখানে আমরা জানি না আমাদের পদ্ধতিতে কতগুলি আর্গুমেন্ট পাস হতে পারে। উদাহরণস্বরূপ, যদি আমাদের একটি ক্যালকুলেটর ক্লাস থাকে যার একটি sumপদ্ধতি রয়েছে। পদ্ধতিটি sum()2 নম্বর, বা 3, বা 5, বা আপনার পছন্দ মতো অনেকগুলি পেতে পারে। sum()প্রতিটি সম্ভাব্য সংখ্যক আর্গুমেন্টের জন্য পদ্ধতিটি ওভারলোড করা খুব অদ্ভুত হবে । পরিবর্তে, আমরা এটি করতে পারি:

public class SimpleCalculator {

   public static int sum(int...numbers) {

       int result = 0;

       for(int i : numbers) {

           result += i;
       }

       return result;
   }

   public static void main(String[] args) {

       System.out.println(sum(1,2,3,4,5));
       System.out.println(sum(2,9));
   }
}
কনসোল আউটপুট:

15
11
এটি আমাদের দেখায় যে জেনেরিকের সাথে সংমিশ্রণে varargs ব্যবহার করার সময় কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে। আসুন নিম্নলিখিত কোডটি দেখি:

import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static <E> void addAll(List<E> list, E... array) {

       for (E element : array) {
           list.add(element);
       }
   }

   public static void main(String[] args) {
       addAll(new ArrayList<String>(), // This is okay
               "Leonardo da Vinci",
               "Vasco de Gama"
       );

       // but here we get a warning
       addAll(new ArrayList<Pair<String, String>>(),
               new Pair<String, String>("Leonardo", "da Vinci"),
               new Pair<String, String>("Vasco", "de Gama")
       );
   }
}
পদ্ধতিটি ইনপুট a এবং যেকোন সংখ্যক অবজেক্ট addAll()হিসাবে নেয় এবং তারপরে এটি এই সমস্ত বস্তুকে তালিকায় যুক্ত করে। পদ্ধতিতে , আমরা আমাদের পদ্ধতিকে দুইবার কল করি। প্রথম ক্ষেত্রে, আমরা দুটি সাধারণ স্ট্রিং যোগ করি । এখানে সবকিছু ঠিক আছে। দ্বিতীয় ক্ষেত্রে, আমরা দুটি বস্তু যোগ করি . কিন্তু এখানে আমরা অপ্রত্যাশিতভাবে একটি সতর্কতা পেয়েছি: List<E>Emain()addAll()ListPair<String, String>List

Unchecked generics array creation for varargs parameter
ওটার মানে কি? কেন আমরা একটি সতর্কতা পেতে পারি এবং কেন একটি উল্লেখ আছে array? সব পরে, আমাদের কোড একটি নেই array! দ্বিতীয় কেস দিয়ে শুরু করা যাক। সতর্কতাটি একটি অ্যারের উল্লেখ করে কারণ কম্পাইলার ভেরিয়েবল-লেংথ আর্গুমেন্টকে (varargs) একটি অ্যারেতে রূপান্তর করে। অন্য কথায়, আমাদের addAll()পদ্ধতির স্বাক্ষর হল:

public static <E> void addAll(List<E> list, E... array)
এটা আসলে এই মত দেখায়:

public static <E> void addAll(List<E> list, E[] array)
অর্থাৎ, পদ্ধতিতে main(), কম্পাইলার আমাদের কোডকে এতে রূপান্তর করে:

public static void main(String[] args) { 
   addAll(new ArrayList<String>(), 
      new String[] { 
        "Leonardo da Vinci", 
        "Vasco de Gama" 
      } 
   ); 
   addAll(new ArrayList<Pair<String,String>>(),
        new Pair<String,String>[] { 
            new Pair<String,String>("Leonardo","da Vinci"), 
            new Pair<String,String>("Vasco","de Gama") 
        } 
   ); 
}
একটি Stringঅ্যারে ঠিক ঠিক আছে. কিন্তু একটি Pair<String, String>অ্যারে না. সমস্যা হল যে Pair<String, String>একটি নন-রিফাইবল টাইপ। সংকলনের সময়, টাইপ আর্গুমেন্ট (<String, String>) সম্পর্কে সমস্ত তথ্য মুছে ফেলা হয়। জাভা-তে অ-পুনঃযোগ্য ধরনের অ্যারে তৈরি করা অনুমোদিত নয় । আপনি যদি ম্যানুয়ালি একটি জোড়া<String, String> অ্যারে তৈরি করার চেষ্টা করেন তবে আপনি এটি দেখতে পারেন

public static void main(String[] args) {

   // Compilation error Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
কারণ সুস্পষ্ট: টাইপ নিরাপত্তা. আপনি যেমন মনে করবেন, একটি অ্যারে তৈরি করার সময়, আপনাকে অবশ্যই নির্দিষ্ট করতে হবে যে অ্যারেটি কোন বস্তু (বা আদিম) সংরক্ষণ করবে।

int array[] = new int[10];
আমাদের পূর্ববর্তী পাঠগুলির একটিতে, আমরা বিস্তারিতভাবে টাইপ ইরেজার পরীক্ষা করেছি। এই ক্ষেত্রে, টাইপ মুছে ফেলার ফলে বস্তুগুলি জোড়া Pairসঞ্চয় করে এমন তথ্য হারাতে পারে । <String, String>অ্যারে তৈরি করা অনিরাপদ হবে। ভারার্গ এবং জেনেরিক জড়িত পদ্ধতিগুলি ব্যবহার করার সময় , টাইপ ইরেজার এবং এটি কীভাবে কাজ করে সে সম্পর্কে মনে রাখতে ভুলবেন না। আপনি যে কোডটি লিখেছেন সে সম্পর্কে আপনি যদি পুরোপুরি নিশ্চিত হন এবং জানেন যে এটি কোনও সমস্যা সৃষ্টি করবে না, আপনি টীকা ব্যবহার করে varargs-সম্পর্কিত সতর্কতাগুলি বন্ধ করতে পারেন।@SafeVarargs

@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
আপনি যদি আপনার পদ্ধতিতে এই টীকা যোগ করেন, আমরা আগে যে সতর্কতাটি পেয়েছি তা প্রদর্শিত হবে না। জেনেরিকের সাথে ভারার্গ ব্যবহার করার সময় আরেকটি সমস্যা হতে পারে তা হল গাদা দূষণ। জেনেরিকের সাথে কাজ করার সময় ভারার্গ ব্যবহার করা - 3নিম্নলিখিত পরিস্থিতিতে গাদা দূষণ ঘটতে পারে:

import java.util.ArrayList;
import java.util.List;

public class Main {

   static List<String> polluteHeap() {
       List numbers = new ArrayList<Number>();
       numbers.add(1);
       List<String> strings = numbers;
       strings.add("");
       return strings;
   }

   public static void main(String[] args) {

       List<String> stringsWithHeapPollution = polluteHeap();

       System.out.println(stringsWithHeapPollution.get(0));
   }
}
কনসোল আউটপুট:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
সহজ কথায়, স্তূপ দূষণ হল যখন টাইপের বস্তুগুলি Aস্তূপে থাকা উচিত, কিন্তু Bটাইপের নিরাপত্তা সংক্রান্ত ত্রুটির কারণে টাইপের বস্তুগুলি সেখানেই শেষ হয়৷ আমাদের উদাহরণে, এই অবিকল কি ঘটবে. প্রথমে, আমরা কাঁচা numbersভেরিয়েবল তৈরি করেছি এবং ArrayList<Number>এটিতে একটি জেনেরিক সংগ্রহ ( ) বরাদ্দ করেছি। 1তারপর আমরা সংগ্রহে নম্বর যোগ .

List<String> strings = numbers;
এই লাইনে, কম্পাইলার " আনচেকড অ্যাসাইনমেন্ট... " সতর্কতা জারি করে সম্ভাব্য ত্রুটি সম্পর্কে আমাদের সতর্ক করার চেষ্টা করেছে, কিন্তু আমরা তা উপেক্ষা করেছি। আমরা টাইপের একটি জেনেরিক ভেরিয়েবল দিয়ে শেষ করি List<String>যা টাইপের জেনেরিক সংগ্রহের দিকে নির্দেশ করে ArrayList<Number>। স্পষ্টতই, এই পরিস্থিতি সমস্যা হতে পারে! এবং তাই এটা করে. আমাদের নতুন ভেরিয়েবল ব্যবহার করে, আমরা সংগ্রহে একটি স্ট্রিং যোগ করি। আমাদের এখন গাদা দূষণ রয়েছে — আমরা প্যারামেট্রিকৃত সংগ্রহে একটি সংখ্যা এবং তারপর একটি স্ট্রিং যোগ করেছি। কম্পাইলার আমাদের সতর্ক করেছে, কিন্তু আমরা তার সতর্কতা উপেক্ষা করেছি। ফলস্বরূপ, ClassCastExceptionপ্রোগ্রামটি চলাকালীন আমরা কেবলমাত্র একটি পাই। তাই এই varargs সঙ্গে কি করতে হবে? জেনেরিকের সাথে ভারার্গ ব্যবহার করলে সহজেই গাদা দূষণ হতে পারে। এখানে একটি সহজ উদাহরণ:

import java.util.Arrays;
import java.util.List;

public class Main {

   static void polluteHeap(List<String>... stringsLists) {
       Object[] array = stringsLists;
       List<Integer> numbersList = Arrays.asList(66,22,44,12);

       array[0] = numbersList;
       String str = stringsLists[0].get(0);
   }

   public static void main(String[] args) {

       List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
       List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");

       polluteHeap(cars1, cars2);
   }
}
এখানে কি হচ্ছে? টাইপ ইরেজারের কারণে, আমাদের পরিবর্তনশীল-দৈর্ঘ্যের যুক্তি

List<String>...stringsLists
তালিকার একটি অ্যারে হয়ে যায়, যেমন List[], একটি অজানা ধরণের বস্তুর (ভুলে যাবেন না যে সংকলনের সময় varargs একটি নিয়মিত অ্যারেতে পরিণত হয়)। এই কারণে, আমরা সহজেই Object[] arrayপদ্ধতির প্রথম লাইনের ভেরিয়েবলে এটি বরাদ্দ করতে পারি — আমাদের তালিকার অবজেক্টের ধরন মুছে ফেলা হয়েছে! এবং এখন আমাদের একটি Object[]ভেরিয়েবল আছে, যেটিতে আমরা কিছু যোগ করতে পারি, যেহেতু জাভাতে সমস্ত অবজেক্ট ইনহেরিট করে Object! প্রথমে, আমাদের কাছে শুধুমাত্র স্ট্রিংগুলির তালিকার একটি অ্যারে আছে। কিন্তু টাইপ ইরেজার এবং আমাদের ভারার্গ ব্যবহার করার জন্য ধন্যবাদ, আমরা সহজেই সংখ্যার একটি তালিকা যোগ করতে পারি, যা আমরা করি। ফলস্বরূপ, আমরা বিভিন্ন ধরণের বস্তু মিশ্রিত করে স্তূপকে দূষিত করি। ClassCastExceptionআমরা অ্যারে থেকে একটি স্ট্রিং পড়ার চেষ্টা করার সময় ফলাফলটি অন্য হবে । কনসোল আউটপুট:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
এই ধরনের অপ্রত্যাশিত পরিণতি varargs ব্যবহার করে হতে পারে, একটি আপাতদৃষ্টিতে সহজ প্রক্রিয়া :) এবং এর সাথে, আজকের পাঠ শেষ হয়। কয়েকটি কাজ সমাধান করতে ভুলবেন না এবং আপনার যদি সময় এবং শক্তি থাকে তবে কিছু অতিরিক্ত পড়া অধ্যয়ন করুন। " কার্যকর জাভা " নিজেই পড়বে না! :) পরের বার পর্যন্ত!
মন্তব্য
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION