جاوا 8 میں جاوا تھریڈز کا تعارف
جاوا 8 کے حصے کے طور پر متعارف کرائی گئی جاوا اسٹریمز کو ڈیٹا کے مجموعے کے ساتھ کام کرنے کے لیے استعمال کیا جاتا ہے۔ وہ خود ڈیٹا ڈھانچہ نہیں ہیں، لیکن حتمی نتیجہ پیدا کرنے کے لیے آرڈر اور پائپ لائننگ کے ذریعے دوسرے ڈیٹا ڈھانچے سے معلومات داخل کرنے کے لیے استعمال کیا جا سکتا ہے۔ نوٹ: یہ ضروری ہے کہ سٹریم اور تھریڈ کو الجھایا نہ جائے، کیونکہ روسی زبان میں دونوں اصطلاحات کو اکثر ایک ہی ترجمہ "بہاؤ" میں کہا جاتا ہے۔ سٹریم آپریشنز کرنے کے لیے ایک آبجیکٹ کو ظاہر کرتا ہے (اکثر ڈیٹا کی منتقلی یا ذخیرہ کرتا ہے)، جب کہ تھریڈ (لفظی ترجمہ - تھریڈ) ایک ایسی چیز کی نشاندہی کرتا ہے جو مخصوص پروگرام کوڈ کو دیگر کوڈ برانچوں کے ساتھ متوازی طور پر انجام دینے کی اجازت دیتا ہے۔ چونکہ اسٹریم ایک علیحدہ ڈیٹا ڈھانچہ نہیں ہے، اس لیے یہ کبھی بھی ڈیٹا کے ماخذ کو تبدیل نہیں کرتا ہے۔ جاوا اسٹریمز میں درج ذیل خصوصیات ہیں:-
جاوا سٹریم کو "java.util.stream" پیکیج کا استعمال کرتے ہوئے استعمال کیا جا سکتا ہے۔ اسے کوڈ کا استعمال کرتے ہوئے اسکرپٹ میں درآمد کیا جاسکتا ہے:
import java.util.stream.* ;
اس کوڈ کا استعمال کرتے ہوئے، ہم جاوا اسٹریم میں کئی بلٹ ان فنکشنز کو بھی آسانی سے نافذ کر سکتے ہیں۔
-
جاوا سٹریم ڈیٹا کے مجموعوں سے ان پٹ کو قبول کر سکتا ہے جیسے کہ جاوا میں مجموعے اور صفیں۔
-
جاوا اسٹریم کو ان پٹ ڈیٹا سٹرکچر کو تبدیل کرنے کی ضرورت نہیں ہے۔
-
جاوا اسٹریم ذریعہ کو تبدیل نہیں کرتا ہے۔ اس کے بجائے، یہ مناسب پائپ لائن طریقوں کا استعمال کرتے ہوئے پیداوار پیدا کرتا ہے۔
-
جاوا اسٹریمز انٹرمیڈیٹ اور ٹرمینل آپریشنز کے تابع ہیں، جن پر ہم مندرجہ ذیل حصوں میں بحث کریں گے۔
-
جاوا اسٹریم میں، انٹرمیڈیٹ آپریشنز پائپ لائن کیے جاتے ہیں اور سست تشخیص کی شکل میں ہوتے ہیں۔ وہ ٹرمینل افعال کے ساتھ ختم ہوتے ہیں۔ یہ جاوا اسٹریم کو استعمال کرنے کے لیے بنیادی فارمیٹ بناتا ہے۔
جاوا 8 میں جاوا اسٹریم بنانا
جاوا تھریڈز کو کئی طریقوں سے بنایا جا سکتا ہے:1. Stream.empty() طریقہ استعمال کرتے ہوئے ایک خالی سلسلہ بنانا
آپ اپنے کوڈ میں بعد میں استعمال کے لیے ایک خالی سلسلہ بنا سکتے ہیں۔ اگر آپ Stream.empty() طریقہ استعمال کرتے ہیں ، تو ایک خالی سلسلہ تیار کیا جائے گا، جس میں کوئی قدر نہیں ہوگی۔ اگر ہم رن ٹائم پر صفر پوائنٹر کی رعایت کو چھوڑنا چاہتے ہیں تو یہ خالی سلسلہ کام آ سکتا ہے۔ ایسا کرنے کے لیے آپ درج ذیل کمانڈ کو استعمال کر سکتے ہیں:Stream<String> str = Stream.empty();
مندرجہ بالا بیان اس کے اندر کسی بھی عناصر کے بغیر str نام کا ایک خالی سلسلہ تیار کرے گا۔ اس کی توثیق کرنے کے لیے، صرف str.count() اصطلاح کا استعمال کرتے ہوئے سٹریم کا نمبر یا سائز چیک کریں ۔ مثال کے طور پر،
System.out.println(str.count());
نتیجے کے طور پر، ہمیں آؤٹ پٹ پر 0 ملتا ہے ۔
2. Stream.builder () طریقہ استعمال کرتے ہوئے Stream.Builder مثال کے ساتھ ایک سلسلہ بنائیں
ہم بلڈر ڈیزائن پیٹرن کا استعمال کرتے ہوئے اسٹریم بنانے کے لیے اسٹریم بلڈر کا بھی استعمال کرسکتے ہیں۔ یہ اشیاء کی مرحلہ وار تعمیر کے لیے ڈیزائن کیا گیا ہے۔ آئیے دیکھتے ہیں کہ ہم Stream Builder کا استعمال کرتے ہوئے ایک سلسلہ کو کیسے شروع کر سکتے ہیں ۔Stream.Builder<Integer> numBuilder = Stream.builder();
numBuilder.add(1).add(2).add( 3);
Stream<Integer> numStream = numBuilder.build();
اس کوڈ کا استعمال کرتے ہوئے، آپ numStream کے نام سے ایک سلسلہ بنا سکتے ہیں جس میں int عناصر ہوں ۔ Stream.Builder مثال جس کو numBuilder کہا جاتا ہے کی بدولت سب کچھ بہت تیزی سے ہو جاتا ہے جو پہلے بنایا گیا ہے۔
3. Stream.of() طریقہ استعمال کرتے ہوئے مخصوص اقدار کے ساتھ ایک سلسلہ بنائیں
سلسلہ بنانے کا ایک اور طریقہ Stream.of() طریقہ استعمال کرنا شامل ہے ۔ یہ دی گئی اقدار کے ساتھ ایک سلسلہ بنانے کا ایک آسان طریقہ ہے۔ یہ اعلان کرتا ہے اور دھاگے کا آغاز بھی کرتا ہے۔ ایک سلسلہ بنانے کے لیے Stream.of() طریقہ استعمال کرنے کی ایک مثال :Stream<Integer> numStream = Stream.of(1, 2, 3);
یہ کوڈ int عناصر پر مشتمل ایک سلسلہ بنائے گا ، جیسا کہ ہم نے Stream.Builder کا استعمال کرتے ہوئے پچھلے طریقہ میں کیا تھا ۔ یہاں ہم نے براہ راست Stream.of() کا استعمال کرتے ہوئے پہلے سے طے شدہ اقدار [1, 2 اور 3] کے ساتھ ایک سلسلہ بنایا ہے ۔
4. Arrays.stream() طریقہ استعمال کرتے ہوئے موجودہ صف سے ایک سلسلہ بنائیں
تھریڈ بنانے کا ایک اور عام طریقہ جاوا میں صفوں کا استعمال شامل ہے۔ یہاں کا سلسلہ Arrays.stream() طریقہ استعمال کرتے ہوئے موجودہ صف سے بنایا گیا ہے ۔ تمام صف کے عناصر کو سٹریم عناصر میں تبدیل کر دیا جاتا ہے۔ یہاں ایک اچھی مثال ہے:Integer[] arr = {1, 2, 3, 4, 5};
Stream<Integer> numStream = Arrays.stream(arr);
یہ کوڈ ایک numStream تیار کرے گا جس میں arr نامی صف کے مواد ہوں گے، جو کہ ایک عددی صف ہے۔
5. Stream.concat() طریقہ استعمال کرتے ہوئے دو موجودہ سلسلے کو ضم کرنا
ایک اور طریقہ جو سٹریم بنانے کے لیے استعمال کیا جا سکتا ہے وہ ہے Stream.concat() طریقہ ۔ یہ دو دھاگوں کو ملا کر ایک دھاگہ بنانے کے لیے استعمال ہوتا ہے۔ دونوں سلسلے ترتیب کے لحاظ سے یکجا ہیں۔ اس کا مطلب ہے کہ پہلا تھریڈ پہلے آتا ہے، اس کے بعد دوسرا تھریڈ آتا ہے، وغیرہ۔ اس طرح کے ربط کی ایک مثال اس طرح نظر آتی ہے:Stream<Integer> numStream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> numStream2 = Stream.of(1, 2, 3);
Stream<Integer> combinedStream = Stream.concat( numStream1, numStream2);
مندرجہ بالا بیان combinedStream کے نام سے ایک حتمی سلسلہ بنائے گا جس میں پہلی سٹریم numStream1 اور دوسری سٹریم numStream2 کے عناصر ایک ایک کر کے ہوں گے ۔
جاوا اسٹریم کے ساتھ آپریشنز کی اقسام
جیسا کہ پہلے ہی ذکر کیا گیا ہے، آپ جاوا 8 میں جاوا اسٹریم کے ساتھ دو قسم کے آپریشن کر سکتے ہیں: انٹرمیڈیٹ اور ٹرمینل۔ آئیے ان میں سے ہر ایک کو مزید تفصیل سے دیکھیں۔انٹرمیڈیٹ آپریشنز
انٹرمیڈیٹ آپریشنز ایک آؤٹ پٹ اسٹریم تیار کرتے ہیں اور صرف اس وقت عمل میں آتے ہیں جب ٹرمینل آپریشن کا سامنا ہوتا ہے۔ اس کا مطلب یہ ہے کہ انٹرمیڈیٹ آپریشنز سستی، پائپ لائن میں کیے جاتے ہیں اور صرف ٹرمینل آپریشن کے ذریعے مکمل کیے جا سکتے ہیں۔ آپ سست تشخیص اور پائپ لائننگ کے بارے میں تھوڑی دیر بعد سیکھیں گے۔ انٹرمیڈیٹ آپریشنز کی مثالیں درج ذیل طریقے ہیں: filter() , map() , different() , peek() , sorted() اور کچھ دیگر۔ٹرمینل آپریشنز
ٹرمینل آپریشنز انٹرمیڈیٹ آپریشنز کو مکمل کرتے ہیں اور آؤٹ پٹ سٹریم کے حتمی نتائج بھی واپس کرتے ہیں۔ چونکہ ٹرمینل آپریشنز سست عمل اور پائپ لائننگ کے خاتمے کا اشارہ دیتے ہیں، اس لیے ٹرمینل آپریشن سے گزرنے کے بعد اس تھریڈ کو دوبارہ استعمال نہیں کیا جا سکتا۔ ٹرمینل آپریشنز کی مثالیں درج ذیل طریقے ہیں: forEach() , collect() , count() , reduce() وغیرہ۔جاوا اسٹریم کے ساتھ آپریشنز کی مثالیں۔
انٹرمیڈیٹ آپریشنز
یہاں کچھ انٹرمیڈیٹ آپریشنز کی کچھ مثالیں ہیں جو جاوا سٹریم پر لاگو کی جا سکتی ہیں:فلٹر ()
یہ طریقہ جاوا میں کسی مخصوص پیشین گوئی سے میل کھاتی ندی سے عناصر کو فلٹر کرنے کے لیے استعمال کیا جاتا ہے۔ یہ فلٹر شدہ آئٹمز پھر ایک نیا سلسلہ بناتے ہیں۔ آئیے بہتر طور پر سمجھنے کے لیے ایک مثال پر ایک نظر ڈالتے ہیں۔Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> even = numStream.filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(even);
نتیجہ:
نقشہ()
یہ طریقہ اصل ان پٹ سٹریم کے عناصر پر میپ شدہ فنکشنز کو انجام دے کر ایک نیا سلسلہ بنانے کے لیے استعمال کیا جاتا ہے۔ شاید نئے سلسلے میں ڈیٹا کی قسم مختلف ہے۔ مثال اس طرح نظر آتی ہے:Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> d = numStream.map(n -> n*2) .collect(Collectors.toList()); System.out.println(d);
نتیجہ:
الگ ()
یہ طریقہ ڈپلیکیٹس کو فلٹر کرکے کسی سلسلے میں صرف انفرادی عناصر کو بازیافت کرنے کے لیے استعمال کیا جاتا ہے۔ اسی کی ایک مثال اس طرح نظر آتی ہے:Stream<Integer> numStream = Stream.of(43,65,1,98,63,63,1); List<Integer> numList = numStream.distinct() .collect(Collectors.toList()); System.out.println(numList);
نتیجہ:
جھانکنا()
یہ طریقہ ٹرمینل آپریشن کو انجام دینے سے پہلے درمیانی تبدیلیوں کو ٹریک کرنے کے لیے استعمال کیا جاتا ہے۔ اس کا مطلب یہ ہے کہ peek() کو سٹریم کے ہر عنصر پر آپریشن کرنے کے لیے استعمال کیا جا سکتا ہے تاکہ ایک سلسلہ بنایا جا سکے جس پر مزید انٹرمیڈیٹ آپریشنز کیے جا سکیں۔Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> nList = numStream.map(n -> n*10) .peek(n->System.out.println("Mapped: "+ n)) .collect(Collectors.toList()); System.out.println(nList);
نتیجہ:
ترتیب شدہ()
sorted() طریقہ کسی سلسلے کے عناصر کو ترتیب دینے کے لیے استعمال کیا جاتا ہے۔ پہلے سے طے شدہ طور پر، یہ عناصر کو صعودی ترتیب میں ترتیب دیتا ہے۔ آپ پیرامیٹر کے طور پر ایک مخصوص ترتیب کی بھی وضاحت کر سکتے ہیں۔ اس طریقہ کار کے نفاذ کی ایک مثال اس طرح نظر آتی ہے:Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.sorted().forEach(n -> System.out.println(n));
نتیجہ:
ٹرمینل آپریشنز
یہاں کچھ ٹرمینل آپریشنز کی کچھ مثالیں ہیں جو جاوا اسٹریمز پر لاگو کی جا سکتی ہیں:ہر ایک کے لئے()
forEach() طریقہ ایک اسٹریم کے تمام عناصر کے ذریعے اعادہ کرنے اور ہر عنصر پر ایک ایک کرکے فنکشن کو انجام دینے کے لیے استعمال کیا جاتا ہے۔ یہ لوپ اسٹیٹمنٹس کے متبادل کے طور پر کام کرتا ہے جیسے کہ for , while اور دیگر۔ مثال:Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); numStream.forEach(n -> System.out.println(n));
نتیجہ:
شمار()
شمار () کا طریقہ سٹریم میں موجود عناصر کی کل تعداد کو بازیافت کرنے کے لیے استعمال کیا جاتا ہے۔ یہ سائز() طریقہ سے ملتا جلتا ہے ، جو اکثر مجموعہ میں عناصر کی کل تعداد کا تعین کرنے کے لیے استعمال ہوتا ہے۔ جاوا اسٹریم کے ساتھ کاؤنٹ() طریقہ استعمال کرنے کی ایک مثال مندرجہ ذیل ہے۔Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); System.out.println(numStream.count());
نتیجہ:
جمع ()
جمع () طریقہ سٹریم عناصر کی تغیر پذیر کمی کو انجام دینے کے لیے استعمال کیا جاتا ہے۔ پروسیسنگ مکمل ہونے کے بعد اسے کسی سلسلے سے مواد کو ہٹانے کے لیے استعمال کیا جا سکتا ہے۔ یہ کمی کو انجام دینے کے لیے کلکٹر کلاس کا استعمال کرتا ہے ۔Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); List<Integer> odd = numStream.filter(n -> n % 2 == 1) .collect(Collectors.toList()); System.out.println(odd);
نتیجہ:
منٹ () اور زیادہ سے زیادہ ()
min() طریقہ ، جیسا کہ نام سے پتہ چلتا ہے، اس میں کم از کم عنصر کو تلاش کرنے کے لیے اس سلسلے میں استعمال کیا جا سکتا ہے۔ اسی طرح، max() طریقہ کو کسی سلسلے میں زیادہ سے زیادہ عنصر تلاش کرنے کے لیے استعمال کیا جا سکتا ہے۔ آئیے یہ سمجھنے کی کوشش کریں کہ انہیں ایک مثال کے ساتھ کیسے استعمال کیا جا سکتا ہے:Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); int smallest = numStream.min((m, n) -> Integer.compare(m, n)).get(); System.out.println("Smallest element: " + smallest);
numStream = Stream.of(43, 65, 1, 98, 63); int largest = numStream.max((m, n) -> Integer.compare(m, n)).get(); System.out.println("Largest element: " + largest);
نتیجہ:
findAny() اور FindFirst()
findAny() سٹریم کے کسی بھی عنصر کو بطور اختیاری لوٹاتا ہے ۔ اگر سلسلہ خالی ہے، تو یہ ایک اختیاری قدر بھی واپس کرے گا ، جو خالی ہو گی۔ findFirst() سٹریم کا پہلا عنصر بطور اختیاری لوٹاتا ہے ۔ جیسا کہ findAny() طریقہ کے ساتھ ، findFirst() طریقہ بھی ایک خالی اختیاری پیرامیٹر واپس کرتا ہے اگر متعلقہ سلسلہ خالی ہے۔ آئیے ان طریقوں کی بنیاد پر درج ذیل مثال پر ایک نظر ڈالتے ہیں۔Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); Optional<Integer> opt = numStream.findFirst();System.out.println(opt); numStream = Stream.empty(); opt = numStream.findAny();System.out.println(opt);
نتیجہ:
allMatch() ، anyMatch() اور noneMatch()
allMatch() طریقہ یہ چیک کرنے کے لیے استعمال کیا جاتا ہے کہ آیا کسی سٹریم میں موجود تمام عناصر کسی خاص پیش گوئی سے میل کھاتے ہیں اور اگر وہ بولین ویلیو سچا کرتے ہیں تو واپس کرتے ہیں، بصورت دیگر غلط لوٹاتا ہے ۔ اگر سلسلہ خالی ہے، تو یہ سچ میں واپس آجاتا ہے ۔ anyMatch() طریقہ یہ چیک کرنے کے لیے استعمال کیا جاتا ہے کہ آیا سٹریم میں موجود عناصر میں سے کوئی ایک مخصوص پیش گوئی سے میل کھاتا ہے۔ اگر ایسا ہے تو یہ سچ لوٹتا ہے، ورنہ غلط ۔ اگر سٹریم خالی ہے، تو یہ غلط لوٹتا ہے ۔ noneMatch() طریقہ درست لوٹاتا ہے اگر سٹریم میں کوئی عنصر پیش گوئی سے میل نہیں کھاتا، اور دوسری صورت میں غلط ۔ اس کی وضاحت کے لیے ایک مثال اس طرح نظر آتی ہے:Stream<Integer> numStream = Stream.of(43, 65, 1, 98, 63); boolean flag = numStream.allMatch(n -> n1); System.out.println(flag); numStream = Stream.of(43, 65, 1, 98, 63); flag = numStream.anyMatch(n -> n1); System.out.println(flag); numStream = Stream.of(43, 65, 1, 98, 63); flag = numStream.noneMatch(n -> n==1);System.out.println(flag);
نتیجہ:
جاوا اسٹریم میں سست تشخیص
جاوا 8 میں جاوا اسٹریمز کے ساتھ کام کرتے وقت سست تشخیص آپٹمائزیشن کا باعث بنتی ہے۔ ان میں بنیادی طور پر انٹرمیڈیٹ آپریشنز میں تاخیر شامل ہوتی ہے جب تک کہ ٹرمینل آپریشن کا سامنا نہ ہو جائے۔ سست تشخیص حسابات پر وسائل کے غیر ضروری ضیاع کو روکنے کے لیے ذمہ دار ہے جب تک کہ نتیجہ درحقیقت مطلوب نہ ہو۔ انٹرمیڈیٹ آپریشنز کے نتیجے میں آؤٹ پٹ سٹریم ٹرمینل آپریشن مکمل ہونے کے بعد ہی پیدا ہوتا ہے۔ سست تشخیص جاوا اسٹریمز میں تمام انٹرمیڈیٹ آپریشنز کے ساتھ کام کرتا ہے۔ لامحدود اسٹریمز کے ساتھ کام کرتے وقت سست تشخیص کا بہت مفید استعمال ہوتا ہے۔ اس طرح، بہت ساری غیر ضروری پروسیسنگ کو روکا جاتا ہے۔جاوا اسٹریم میں پائپ لائنز
جاوا سٹریم میں ایک پائپ لائن ایک ان پٹ سٹریم پر مشتمل ہوتی ہے، صفر یا اس سے زیادہ انٹرمیڈیٹ آپریشنز ایک کے بعد ایک قطار میں ہوتے ہیں، اور آخر میں ایک ٹرمینل آپریشن۔ جاوا اسٹریمز میں انٹرمیڈیٹ آپریشن سستی سے انجام پاتے ہیں۔ یہ پائپ لائن انٹرمیڈیٹ آپریشنز کو ناگزیر بنا دیتا ہے۔ پائپ لائنوں کے ساتھ، جو بنیادی طور پر درمیانی آپریشنز ہیں، ترتیب میں مل کر، سستی سے عملدرآمد ممکن ہو جاتا ہے۔ پائپ لائنز ان انٹرمیڈیٹ آپریشنز کا سراغ لگانے میں مدد کرتی ہیں جنہیں ٹرمینل آپریشن کے آخر میں سامنا ہونے کے بعد انجام دینے کی ضرورت ہوتی ہے۔نتیجہ
آئیے اب خلاصہ کرتے ہیں جو ہم نے آج سیکھا ہے۔ اس مضمون میں:- ہم نے اس پر ایک سرسری نظر ڈالی کہ جاوا اسٹریمز کیا ہیں۔
- پھر ہم نے جاوا 8 میں جاوا تھریڈز بنانے کے لیے بہت سی مختلف تکنیکیں سیکھیں۔
- ہم نے دو اہم قسم کے آپریشنز (انٹرمیڈیٹ آپریشنز اور ٹرمینل آپریشنز) سیکھے جو جاوا اسٹریمز پر کیے جا سکتے ہیں۔
- اس کے بعد ہم نے انٹرمیڈیٹ اور ٹرمینل دونوں کارروائیوں کی کئی مثالوں کو تفصیل سے دیکھا۔
- ہم نے سست تشخیص کے بارے میں مزید معلومات حاصل کی اور آخر میں جاوا تھریڈز میں پائپ لائننگ کے بارے میں سیکھا۔
GO TO FULL VERSION