Method Reference در Lambda
در سری مقالات آموزش جاوا, مبحث method reference در Lambda را مورد بررسی قرارمی دهیم.
با استفاده از method reference میتوان یک متد را با استفاده از نام آن فراخوانی کرد. همانطور که در مقالات قبل اشاره شد, میتوان یک متد را به عنوان یک متغیر به متد دیگری ارسال کرد. میتوان method reference را در موارد زیر استفاده نمود:
- متد های static
- به متد instance از یک object
- به متد Constructor
برای درک بهتر مثال هایی از هریک از روش ها بررسی میکنیم. در مقاله قبل، مثالی را بررسی کردیم که اسامی با حرف اول a را در خروجی چاپ میکرد. حال میخواهیم این مثال را با استفاده از static method reference انجام دهیم:
public static void main(String[] args) { List<String> names = Arrays.asList("Vahid", "Ali", "Amir", "Mohammad", "Moein", "Kazem"); print(names, Names::isValid); } public static boolean isValid(String s) { return (s.toLowerCase().startsWith("a")); } public static void print(List<String> strings, Predicate<String> stringPredicate) { for (String s : strings) { if (stringPredicate.test(s)) { System.out.println(s); } } }
در کد بالا دیگر پارامتری را به متد isValid ارسال نکردیم. در هنگام اجرا این عمل توسط Compiler انجام میشود.
در lambda expression وقتی میخواهیم از متد کلاسی استفاده کنیم، نیاز است تا یک instance از آن و پارامتر های مورد نیازآن را ارجاع دهیم. اما با استفاده از method reference تنها یک لیست از پارامتر ها و نام متد مورد نظر را به آن ارسال میکنیم وعمل ارجاع به صورت خودکار انجام می شود. برای استفاده از instance method reference باید از یک functional Interface به نام Function استفاده شود. این functional interface یک پارامتر ورودی دریافت میکند و یک پارامتر در خروجی برمیگرداند. ساختار Function Interface به این صورت است:
public interface Function<T, R> R apply(T t);
T مشخص کننده نوع ورودی و R مشخص کننده نوع خروجی است. یک متد با نام apply دارد که همانطور که مشخص است متناسب با ورودی خود, نوع متغیر مورد انتظاری را به خروجی ارسال میکند. اگر بخواهیم مثال بالا را طوری بنویسیم که نام هر شخص درون یک کلاس به شرح زیر قرار بگیرد:
public class User { String username; public User(String username) { this.username = username; } public String getUsername() { return username; } }
باید کد به این صورت تغییر کند:
public static void main(String[] args) { List<User> users = Arrays.asList(new User("Vahid"), new User("Ali"), new User("Amir"), new User("Mohammad"), new User("Moein"), new User("Kazem")); print(function(users, User::getUsername), Names::isValid); } public static boolean isValid(String s) { return (s.toLowerCase().startsWith("a")); } public static void print(List<String> strings, Predicate<String> stringPredicate) { for (String s : strings) { if (stringPredicate.test(s)) { System.out.println(s); } } } public static List<String> function(List<User> users, Function<User, String> stringFunction) { List<String> name = new ArrayList<>(); for (User user : users) { name.add(stringFunction.apply(user)); } return name; }
در کد بالا یک متد اضافه شده است که نوع ورودی Function interface آن از نوع کلاس user است و نوع String برمیگرداند. دستوری که به این متد ارسال شده است به این صورت است:
function(users, User::getUsername)
و به این صورت توانستیم به متد درون Object های کلاس User دسترسی پیدا کنیم.
با استفاده از Constructor method reference میتوان instance هایی از روی object ها ایجاد کرد. در اینجا نیز به یک Function Interface نیاز داریم تا با دریافت پارامتر های مورد نیاز Constructor یک خروجی از نوع کلاس برای ما برگرداند. اگر بخواهیم کد بالا را طوری تغییر دهیم که دیگر نیازی نباشد تا از روی کلاس ها با دستور new یک instance ایجاد کنیم, کد را باید به این صورت تغییر دهیم:
Function<String, User> user = User::new; List<User> users = Arrays.asList(user.apply("Vahid"), user.apply("Ali"), user.apply("Amir"), user.apply("Mohammad"), user.apply("Moein"), user.apply("Kazem"));
در حقیقت این کد دقیقا همان کاری که دستور new در کد بالا انجام میداد را انجام میدهد. در ابتدا با استفاده از دستور User::new مشخص کرده ایم که میخواهیم از روش Constructor method Reference استفاده کنیم. سپس با استفاده از متد apply پارامتر های مورد نیاز Constructor را ارجاع میدهیم. برای تسلط داشتن برمفاهیم lambda و همچنین استفاده بهتر از آن، لازم است بر Functional Interface های آن تسلط کافی داشته باشید. تمام مفاهیم پرکاربرد lambda در عمل بر پایه Functional Interface ها قرار دارد.
در مقاله بعد به مفهوم foreach و stream در lambda میپردازیم.
سری مقالات آموزش lambda ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.