آشنایی با Stream در جاوا و اندروید
Stream, ابزاری است که توسط شرکت Oracle, در جاوا ۸ معرفی شد. در این مقاله قصد داریم تا مبحث Stream را به صورت اجمالی مورد بررسی قرار دهیم. برای درک بهتر Stream, بهتر است با برنامه نویسی با استفاده از Lambda آشنا باشید.
بر اساس تعریف, Stream به مجموعه کلاس هایی اتلاق میشود که پردازش Fuctional Style را پشتیبانی میکنند. همانطور که در مبحث Lambda, توضیح داده شد, Fuctional Programming برای مواقعی است که پردازش ها متغیر و موجودیت ها ثابت هستند. بنابراین, با استفاده از Stream نیز میتوانیم پردازش هایی را به صورت Functional انجام دهیم. ممکن است برخی این کلاس را مشابه با کلاس InputStream و OutputStream بدانند.اما تشابهی در این بین وجود ندارد. در حقیقت این کلاس بر روی رشته ای موجودیت ها پردازش هایی را انجام میدهد.
کلاس هایی که امکان نگهداری رشته ای داده ها را دارند, از Stream پشتیبانی میکنند:
/// Arrays String[] arrayStrings=new String[10]; Arrays.stream(arrayStrings).... /// List List<String> listStrings = new ArrayList<>(); listStrings.stream()....
همچنین میتوانیم از خود کلاس Stream نیز برای نگهداری رشته ای از موجودیت ها استفاده کنیم:
Stream.of(1,2,3,4,5)
اکنون متد های پرکاربرد Stream را مورد بررسی قرار میدهیم.
Count
از این متد برای محاسبه تعداد اعضای موجود در Stream استفاده میشود. این متد مشابه متد Size در کلاس List و مشابه Length در کلاس Array است. وقتی پردازش های گوناگونی بر روی رشته ای از داده ها صورت میگیرد, ممکن است بر اساس پردازش های اعمالی, بخشی از داده ها انتخاب شوند. با استفاده از این متد میتوانیم تعداد داده های موجود را بررسی کنیم. اگر پردازش بر روی داده ها اعمال نشود, Count تعداد اعضای رشته را برمیگرداند:
java.util.List<String> names = new ArrayList<>(); names.add("Zero"); names.add("To"); names.add("Hero"); System.out.println(names.stream().count()); //// Output : 3
ForEach
وقتی یک رشته ای از داده ها داریم و بخواهیم یک دستور را بر روی تک تک اعضای آن اجرا کنیم, از این دستور استفاده میشود. رفتار این متد کاملا مشابه دستور تکرار enhance for است:
for (Object object : arraysOfObject) { }
دستورات درون متد forEach میتوانند به صورت Lambda و یا Method Refrence باشند:
names.stream().forEach(System.out::println);
Distinct
ممکن است یک لیست شامل داده ها مشابه و تکراری باشد. اگر بخواهیم این داده های تکرار شده را حذف کنیم از این متد استفاده میکنیم. در اینجا باید توجه داشته باشیم که اگر داده های لیست از نوع Object های کلاس هستند, هر داده با داده های دیگر متفاوت است.برای مثال, یک کلاس مدل داریم و دو Object از روی آن ایجاد کردهایم و هر دو Object خواص یکسانی را نگهداری میکنند. چون به هریک از Object ها فضای مجزایی اختصاص داده شده است, این دو Object با یکدیگر متفاوت هستند.
names.stream().distinct().forEach(System.out::println);
Collect
اگر بخواهیم نتیجه را در یک لیست نگهداری کنیم از این متد استفاده میکنیم. برای استفاده از این متد, نیاز است تا یکی از متد های کلاس collectors را به آن ارسال کنیم و مشخص کنیم که بر چه اساسی لیست ایجاد شود. در واقع پس از انجام پردازش های مد نظر بر روی رشته ای از داده ها, میتوانیم آنها را با ساختار تعریف شده, در قالب یک لیست نگهداری کنیم:
List<String> distincNames = names.stream().distinct().collect(Collectors.toList());
Map
از این متد برای تبدیل داده های رشته استفاده میکنیم. این متد بر روی تمام داده ها تغییر اعمال میکند. برای مثال, یک لیست از مدل دادهای برای نگهداری اطالاعات اعضا داریم. با استفاده از این متد میتوانیم از یک خاصیت مشخص مدل در قالب لیست استفاده کنیم. عمل Mapping در اندروید میتواند بسیار پرکاربرد باشد. برای مثال, اگر یک لیست از EditText ها داشته باشیم و بخواهیم مقادیر تمام آنها را دریافت کنیم, با استفاده از Mapping, داده ها را از نوع View به نوع String تبدیل میکنیم.
Model zero = new Model("Zero"); Model zeroDup = new Model("Zero"); Model to = new Model("To"); Model hero = new Model("Hero"); ArrayList<Model> models = new ArrayList<>(); models.add(zero); models.add(zeroDup); models.add(to); models.add(hero); List<String > modelNames= models.stream().map(Model::getName).distinct().collect(Collectors.toList()); modelNames.forEach(System.out::println);
Filter
وقتی بخواهیم شرط خاصی را روی رشته داده های Stream اعمال کنیم, از این متد استفاده میکنیم. در واقع دستورات شرطی در این متد قرار میگیرند. در این متد ها میتوانیم از Function Interface ها نیز استفاده کنیم.
List<String > modelNames= models.stream() .map(Model::getName).map(String::toLowerCase).distinct() .filter(name->name.startsWith("z")) .collect(Collectors.toList());
توجه داشته باشید که ترتیب پردازش ها بر روی داده ها بسیار اهمیت دارد. در کد فوق, ابتدا مدل ها را به خاصیت String تبدیل کردیم و سپس کارکتر های نام های حاصل را به حروف کوچک تبدیل کردهایم. جابجایی در ترتیب این دستورات میتواند نتیجه را تغییر دهد.
Stream ها در اندروید از نسخه اندروید ۶ به بعد قابل استفاده است. بنابراین اگر بخواهیم از این library در تمام نسخه های اندروید استفاده کنیم, نیاز است تا یک library جانبی به پروژه اضافه کنیم. gradle dependency این library را باید به gradle.build اضافه کنیم:
compile 'com.annimon:stream:1.1.8'
سپس میتوانیم از آن در اندروید نیز استفاده کنیم:
Stream.of(listViewFont).forEach(e -> e.setTypeface(getFont(context)));
در این مقاله سعی بر این شد تا با مفهوم Stream و کاربرد آن آشنا شویم. البته این مقاله صرفا جهت آشنایی با این library است و در طی مقالات بعد, بیشتر از این library استفاده خواهیم کرد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.