Function Interface ها در Lambda
در سری مقالات آموزش جاوا, به مبحث Function Interface ها در Lambda میپردازیم.
در مقالات قبل توضیحاتی پیرامون شیوه برنامه نویسی با استفاده از Lambda ارائه شد. در ابتدا مفاهیم پیشرفته تری پیرامون Function Interface ها ارائه میدهیم. برای مثال فرض کنید چنین قطعه کدی داریم و میخواهیم یک لیست از اسامی را با یک فیلتر مشخص نمایش دهیم. برای مثال اسامی که حرف اول آنها با a شروع میشود را میخواهیم چاپ کنیم:
public static void main(String[] args) { List<String> names = Arrays.asList("Vahid", "Ali", "Amir", "Mohammad", "Moein", "Kazem"); print(names,p->p.toLowerCase().startsWith("a")); } public static void print(List<String> names, Condition condition) { for (String s : names) { if (condition.check(s)) { System.out.println(s); } } } interface Condition{ boolean check(String b); }
در اینجا ما یک function interface داریم که در lambda به ما کمک میکند بتوانیم شرط را پیاده سازی کنیم. اما تعریف یک interface گاهی یک امر بیهوده است. زیرا بسیاری از چنین interface هایی از قبل ایجاد شده اند و تنها باید آنها را به درون کد وارد کرد. لیست این interface ها را میتوانید از اینجا مشاهده کنید. برای مثال بجای ایجاد Condition Interface میتوان از Predicate Interface استفاده کرد و همانطور که از تعریف آن مشخص است, یک نتیجه را به صورت boolean برمیگرداند و کاملا مشابه interface ما است. حال متد print را به این صورت تغییر میدهیم:
public static void print(List<String> names, Predicate<String> condition) { for (String s : names) { if (condition.test(s)) { System.out.println(s); } } }
البته چون Lambda نسبت به نام interface حساس نیست و تنها به فعالیت درون آن توجه میکند, بنابراین نیازی به تغییر در Lambda Expression نیست. برای درک بهتر یک مثال دیگر را بررسی میکنیم. اگر بخواهیم interface داشته باشیم که یک پارامتر را دریافت کند و مقداری را برنگرداند, بهتر است از Consumer Interface استفاده کنیم. برای مثال:
public static void main(String[] args) { List<String> names = Arrays.asList("Vahid", "Ali", "Amir", "Mohammad", "Moein", "Kazem"); print(names,p->p.toLowerCase().startsWith("a"),p-> System.out.println(p)); } public static void print(List<String> names, Predicate<String> condition, Consumer consumer) { for (String s : names) { if (condition.test(s)) { consumer.accept(s); } } }
در اینجا دستور چاپ مقداری را برنمیگرداند. در نتیجه به عنوان یک پارامتر میتواند به متد درون Consumer interface ارسال شود و با متد accept آن را انجام دهد. با مراجعه به لیست Function Interface ها میتوانید Interface های مورد نیاز خود را پیدا کنید و دیگر نیازی به پیاده سازی آنها ندارید.
یکی از مهم ترین قسمت های کد نویسی جاوا مبحث try-Catch میباشد. اگر بخواهیم پیاده سازی آن را با Lambda نمایش دهیم میتوان به این صورت عمل کرد:
public static void main(String[] args) { int[] nums = {1, 2, 3}; int[] d = {2, 0}; div(nums, d, (a, b) -> System.out.println(a / b)); } public static void div(int[] nums, int[] d, BiConsumer<Integer, Integer> consumer) { for (int a : nums) { for (int b : d) { try { consumer.accept(a, b); } catch (ArithmeticException e) { System.out.println(e.getMessage()); } } } }
در اینجا BitConsumer Interface دو پارامتر ورودی دریافت میکند اما مقداری را برنمیگرداند. میتوان کد بالا را به این صورت تغییر داد و try-catch درون Lambda Expression قرار داد:
div(nums, d, (a, b) ->{ try { System.out.println(a / b); } catch (ArithmeticException e) { System.out.println(e); }});
اما بهتر است با استفاده از یک متد این کار را انجام دهیم تا خوانایی کد ها افزایش یابد:
public static void main(String[] args) { int[] nums = {1, 2, 3}; int[] d = {2, 0}; div(nums, d, handler((a, b) -> System.out.println(a / b))); } public static BiConsumer<Integer,Integer> handler(BiConsumer<Integer,Integer> consumer) { return (a,b)->{ try { consumer.accept(a, b); } catch (ArithmeticException e) { System.out.println(e); } }; }
به این ترتیب یک متد نقش کنترل کننده خطا را ایفا میکند و در صورت نبود خطایی دستور چاپ را انجام میدهد.
در این مقاله سعی براین شد تا درک بهتری نسبت به Function Interface ها ایجاد شود. در مقاله بعدی به مبحث method reference ها میپردازیم.
سری مقالات آموزش lambda ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.