دیدید که Lambda Expression در واقع پیادهسازی یک متد است: تنها متد abstract یک Functional Interface. گاهی اوقات مردم این Lambda Expressionها را «متدهای بدون نام (Anonymous Methods)» مینامند، چون دقیقاً همین هستند: متدی بدون نام که میتوانید آن را در برنامهتان جابهجا کنید، در فیلد یا متغیر ذخیره کنید، به عنوان آرگومان به متد یا Constructor ارسال کنید و از متد برگردانید.
گاهی اوقات Lambda Expressionهایی مینویسید که فقط فراخوانی متدهای خاص تعریفشده در جای دیگر هستند. و در واقع، قبلاً این کار را با نوشتن کد زیر انجام دادهاید:
Consumer<String> printer = s -> IO.println(s);
به این شکل نوشته شده، این Lambda Expression فقط ارجاعی به متد println() تعریفشده روی شی System.out است.
اینجاست که سینتکس Method Reference وارد میشود.
---گاهی اوقات Lambda Expression فقط ارجاعی به متد موجود است. در آن صورت میتوانید آن را به صورت Method Reference بنویسید. کد قبلی به این صورت در میآید:
Consumer<String> printer = IO::println;
چهار دسته Method Reference وجود دارد:
Consumer printer به دستهی Bound Method Referenceها تعلق دارد.
---بیشتر اوقات IDE شما میتواند بگوید آیا Lambda Expression خاصی میتواند به Method Reference نوشته شود. تردید نکنید!
فرض کنید کد زیر را دارید:
DoubleUnaryOperator sqrt = a -> Math.sqrt(a);
این Lambda Expression در واقع ارجاعی به متد static Math.sqrt() است. میتواند به این شکل نوشته شود:
DoubleUnaryOperator sqrt = Math::sqrt;
این Method Reference خاص به متد static ارجاع میدهد و بنابراین Static Method Reference نامیده میشود. سینتکس کلی Static Method Reference برابر RefType::staticMethod است.
Static Method Reference میتواند بیش از یک آرگومان بگیرد. کد زیر را در نظر بگیرید:
IntBinaryOperator max = (a, b) -> Integer.max(a, b);
میتوانید آن را با Method Reference بازنویسی کنید:
IntBinaryOperator max = Integer::max;
---
فرض کنید کد زیر را دارید:
Function<String, Integer> toLength = s -> s.length();
این Function را میتوان به صورت ToIntFunction<T> نوشت. فقط ارجاعی به متد length() کلاس String است. پس میتوانید آن را به صورت Method Reference بنویسید:
Function<String, Integer> toLength = String::length;
این سینتکس در نگاه اول ممکن است گیجکننده باشد چون واقعاً شبیه فراخوانی static به نظر میرسد. اما در واقع نیست: متد length() متد instance کلاس String است.
میتوانید هر getter را از یک Java Bean ساده با چنین Method Referenceای فراخوانی کنید. فرض کنید کلاس User با متد getName() دارید. Function زیر را میتوانید بنویسید:
Function<User, String> getName = user -> user.getName();
به صورت Method Reference زیر:
Function<User, String> getName = User::getName;
مثال دیگری که قبلاً دیدهاید:
BiFunction<String, String, Integer> indexOf = (sentence, word) -> sentence.indexOf(word);
این Lambda در واقع ارجاعی به متد indexOf() کلاس String است:
BiFunction<String, String, Integer> indexOf = String::indexOf;
سینتکس کلی Unbound Method Reference: RefType::instanceMethod که RefType نام نوع و instanceMethod نام متد instance است.
اولین مثال Method Reference که دیدید:
Consumer<String> printer = IO::println;
این Method Reference Bound نامیده میشود چون شیای که متد روی آن فراخوانی میشود در خود Method Reference تعریف شده. پس این فراخوانی به شی دادهشده در Method Reference محدود (Bound) است.
اگر سینتکس Unbound را در نظر بگیرید: Person::getName، میبینید شیای که متد روی آن فراخوانی میشود بخشی از این سینتکس نیست: به عنوان آرگومان Lambda Expression ارائه میشود.
Function<User, String> getName = User::getName;
User anna = new User("Anna");
String name = getName.apply(anna);
میبینید Function به نمونهی خاصی از User اعمال میشود که به Function ارسال شده.
سینتکس کلی Bound Method Reference: expr::instanceMethod که expr عبارتی است که شی برمیگرداند و instanceMethod نام متد instance است.
آخرین نوع Method Reference که باید بدانید Constructor Method Reference است. فرض کنید Supplier<List<String>> زیر را دارید:
Supplier<List<String>> newListOfStrings = () -> new ArrayList<>();
میبینید این در واقع ارجاعی به Constructor بدون پارامتر ArrayList است. Method Reference میتواند این کار را انجام دهد. اما چون Constructor متد نیست، این دستهی دیگری از Method Referenceهاست:
Supplier<List<String>> newListOfStrings = ArrayList::new;
توجه کنید عملگر Diamond اینجا لازم نیست. اگر بخواهید آن را بگذارید، باید نوع را هم ارائه دهید:
Supplier<List<String>> newListOfStrings = ArrayList<String>::new;
باید بدانید اگر نوع Method Reference را ندانید، نمیتوانید دقیقاً بگویید چه کاری انجام میدهد. مثال:
Supplier<List<String>> newListOfStrings = () -> new ArrayList<>();
Function<Integer, List<String>> newListOfNStrings = size -> new ArrayList<>(size);
هر دو متغیر newListOfStrings و newListOfNStrings با سینتکس یکسان ArrayList::new نوشته میشوند اما به یک Constructor ارجاع نمیدهند. فقط باید مراقب باشید.
چهار نوع Method Reference:
| نام | سینتکس | معادل Lambda |
|---|---|---|
| Static | RefType::staticMethod | (args) -> RefType.staticMethod(args) |
| Bound | expr::instanceMethod | (args) -> expr.instanceMethod(args) |
| Unbound | RefType::instanceMethod | (arg0, rest) -> arg0.instanceMethod(rest) |
| Constructor | ClassName::new | (args) -> new ClassName(args) |
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/