در مقالههای قبلی این مجموعه آموزشی، نحوهی تبدیل حلقههای حاوی if یا دستورات شرطی در سبک دستوری (Imperative) به سبک تابعی (Functional) را بررسی کردیم. در این مقاله میبینیم چگونه حلقهای که داده را تبدیل (Transform) میکند به سبک تابعی تبدیل شود. علاوه بر آن، کدی که تبدیل داده و انتخاب گزینشی عناصر را قبل از تبدیل ترکیب میکند هم بازنویسی خواهیم کرد.
هر جا در یک حلقهی سبک دستوری در حال تبدیل داده هستید، میتوانید از تابع map() در سبک تابعی استفاده کنید. بیایید ببینیم چگونه این کار انجام میشود.
در اینجا مثالی از حلقهی foreach میبینیم که نامهای یک مجموعه را به حروف بزرگ (Uppercase) تبدیل میکند:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
IO.println(name.toUpperCase());
}
در هر قدم از حلقه، متغیر name به مقدار جدیدی متصل میشود. همانطور که حلقه از یک عنصر به عنصر بعدی در مجموعهی دادهشده پیشروی میکند، هر نام با استفاده از تابع toUpperCase() به حروف بزرگ تبدیل شده و مقدار نتیجه چاپ میشود. در مقالهی قبلی دیدیم چگونه foreach سبک دستوری را به سبک تابعی تبدیل کنیم — با استفاده از stream() بهعنوان iterator داخلی. اگر صرفاً همان روش قبلی را اعمال کنیم، کد تابعی حاصل ناهنجار و سختخوان خواهد بود، چون Lambda پاسدادهشده به forEach همزمان عمل تبدیل و عمل چاپ را انجام میدهد، به این صورت:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.forEach(name -> IO.println(name.toUpperCase())); //Don't do this
اگرچه این کد تابعی همان نتیجهی کد سبک دستوری را تولید میکند، اما Lambda پاسدادهشده به تابع forEach() Cohesive (یکپارچه) نیست، خواندنش سخت است و تغییر دادنش دشوار میباشد.
قبل از بازنویسی کد سبک دستوری بالا به سبک تابعی، ابتدا باید کد سبک دستوری را به یک نسخهی دستوری دیگر بازنویسی کنیم تا هر خط Cohesiveتر و یکپارچهتر شود، به این صورت:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
String nameInUpperCase = name.toUpperCase();
IO.println(nameInUpperCase);
}
از مقالههای قبلی این مجموعه میدانیم که for میتواند به stream() تبدیل شود و چاپ مقادیر از طریق forEach() انجام گردد. آنچه باقی میماند، عملیات تبدیل (Transformation) است — یعنی فراخوانی تابع toUpperCase(). چنین تبدیلهایی را میتوان با استفاده از عملیات map() روی stream() انجام داد.
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(name -> name.toUpperCase())
.forEach(nameInUpperCase -> IO.println(nameInUpperCase));
عملیات map() داده را بر اساس تابعی که از Lambda Expression پاسدادهشده به map() فراخوانی میشود، به مقدار دیگری تبدیل میکند. در این مثال، هر نام به مقدار بزرگنویس (Uppercase) خود تبدیل شده. مقدار تبدیلشده سپس از Lambda Expressionای که به forEach() پاس داده شده چاپ میشود.
میتوانیم کد را با استفاده از ارجاع متد (Method Reference) بهجای Lambda Expression مختصرتر کنیم، به این صورت:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(String::toUpperCase)
.forEach(IO::println);
از تابع map() برای تبدیل داده در حین حلقهزدن روی مجموعهای از داده استفاده کنید.
فرض کنید در میانهی حلقه، میخواهیم بعضی مقادیر را از مجموعه بر اساس شرطی خاص انتخاب کنیم و فقط روی آن عناصر خاص تبدیل اعمال نماییم. مثلاً اگر فقط نامهایی با طول ۴ کاراکتر را تبدیل و چاپ کنیم؟ در سبک دستوری اینطور عمل میکنیم:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
if(name.length() == 4) {
IO.println(name.toUpperCase());
}
}
میدانیم که دستور if سبک دستوری را میتوان به تابع filter() در سبک تابعی بازنویسی کرد. میتوانیم عملیات تبدیل را با استفاده از map() بعد از عملیات filter() انجام دهیم، به این صورت:
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.filter(name -> name.length() == 4)
.map(String::toUpperCase)
.forEach(IO::println);
تابع filter() دادهی نامطلوب و اضافی را حذف میکند و فقط مقادیری را که میخواهیم استفاده کنیم عبور میدهد. تابع map() مقادیری را که بعد از filter باقی ماندهاند تبدیل میکند.
هر جا تبدیل داده درون حلقهی for دیدید، از تابع map() برای اعمال تبدیل در سبک تابعی استفاده کنید. علاوه بر آن، اگر بدنهی حلقه شامل دستور if برای انتخاب گزینشی بعضی مقادیر جهت تبدیل است، آنگاه از API stream() با فراخوانی متد filter() قبل از استفاده از متد map() استفاده نمایید.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/