CodeGym /جاوا بلاگ /Random-UR /جنرک کے ساتھ کام کرتے وقت varargs کا استعمال کرنا
John Squirrels
سطح
San Francisco

جنرک کے ساتھ کام کرتے وقت varargs کا استعمال کرنا

گروپ میں شائع ہوا۔
ہائے! آج کے اسباق میں، ہم عمومیات کا مطالعہ جاری رکھیں گے۔ جیسا کہ یہ ہوتا ہے، یہ ایک بڑا موضوع ہے، لیکن اس سے گریز کرنے کی کوئی ضرورت نہیں ہے — یہ زبان کا ایک انتہائی اہم حصہ ہے :) جب آپ اوریکل دستاویزات کا جنرکس پر مطالعہ کرتے ہیں یا آن لائن ٹیوٹوریل پڑھتے ہیں، تو آپ کو غیر قابل تصدیق اقسام اور اصطلاحات نظر آئیں گی۔ قابل تجدید اقسام قابل تجدید قسم ایک قسم ہے جس کے لیے رن ٹائم پر معلومات مکمل طور پر دستیاب ہوتی ہے۔ جاوا میں، اس طرح کی اقسام میں قدیم، خام قسمیں، اور غیر عام قسمیں شامل ہیں۔ اس کے برعکس، ناقابل اصلاح قسمیں وہ قسمیں ہیں جن کی معلومات مٹ جاتی ہیں اور رن ٹائم پر ناقابل رسائی ہو جاتی ہیں۔ جیسا کہ یہ ہوتا ہے، یہ generics ہیں — List<String>, List<Integer>وغیرہ۔

ویسے آپ کو یاد ہے کہ وررگس کیا ہے؟

اگر آپ بھول گئے ہیں، تو یہ ایک متغیر لمبائی کی دلیل ہے۔ وہ ایسے حالات میں کارآمد ہیں جہاں ہم نہیں جانتے کہ ہمارے طریقہ کار پر کتنے دلائل گزر سکتے ہیں۔ مثال کے طور پر، اگر ہمارے پاس ایک کیلکولیٹر کلاس ہے جس کا ایک 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
اس سے ہمیں پتہ چلتا ہے کہ ورارگس کو جنرک کے ساتھ ملا کر استعمال کرتے وقت کچھ اہم خصوصیات ہیں۔ آئیے درج ذیل کوڈ کو دیکھیں:
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")
       );
   }
}
یہ addAll()طریقہ ان پٹ a List<E>اور کسی بھی تعداد میں Eاشیاء کے طور پر لیتا ہے، اور پھر یہ ان تمام اشیاء کو فہرست میں شامل کرتا ہے۔ طریقہ کار میں main()، ہم اپنے addAll()طریقہ کو دو بار کہتے ہیں۔ پہلی صورت میں، ہم دو عام تاریں شامل کرتے ہیں List۔ یہاں سب کچھ ترتیب میں ہے۔ دوسری صورت میں، ہم دو Pair<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 اور generics شامل ہوں، ٹائپ ایریزر اور یہ کیسے کام کرتا ہے کے بارے میں یاد رکھیں۔ @SafeVarargsاگر آپ اپنے لکھے ہوئے کوڈ کے بارے میں قطعی طور پر یقین رکھتے ہیں اور جانتے ہیں کہ اس سے کوئی مسئلہ نہیں ہوگا، تو آپ تشریحات کا استعمال کرتے ہوئے varargs سے متعلق وارننگز کو بند کر سکتے ہیں۔
@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! سب سے پہلے، ہمارے پاس صرف تاروں کی فہرستوں کی ایک صف ہے۔ لیکن ٹائپ erasure اور ہمارے varargs کے استعمال کی بدولت، ہم آسانی سے نمبروں کی فہرست شامل کر سکتے ہیں، جو ہم کرتے ہیں۔ نتیجے کے طور پر، ہم مختلف اقسام کی اشیاء کو ملا کر ڈھیر کو آلودہ کرتے ہیں۔ 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