في المرة الأولى التي تعرضت فيها لتعبيرات Lambda كانت في TypeScript (مجموعة Superset of JavaScript) ، وكان ذلك لجعل طريقة TypeScript خارج هذه الطريقة بدلاً من هذه الطريقة. بعد استخدامه ، أدركت فجأة أن Lambda ليس ميزة جديدة للوزن الثقيل لـ JDK8؟ لذلك شعرت أنني راجعت المعلومات ذات الصلة وسجلتها:
1. المعلمة السلوك
باختصار ، يعني المعلمة السلوك أن جسم الوظيفة يحتوي فقط على رمز عام يشبه القالب ، في حين يتم تمرير بعض المنطق الذي يتغير مع سيناريو العمل إلى الوظيفة في شكل معلمات. يمكن أن يؤدي استخدام معلمة السلوك إلى جعل البرنامج أكثر عمومية للتعامل مع احتياجات التغييرات المتكررة.
فكر في سيناريو العمل ، على افتراض أننا بحاجة إلى تصفية Apple من خلال برنامج ، نحدد أولاً كيان Apple:
الفئة العامة Apple {/* number*/private long id ؛/** color*/private color color ؛/** weight*/private float weight ؛/** Origin*/private string Origin ؛ public Apple () {} Apple Apple (id long ، color color ، there intern ، string) {this.id = id ؛ this.color = color ؛ this.weight ؛ this.قد يكون الطلب الأولي للمستخدمين ببساطة تصفية التفاح الخضراء من خلال البرنامج ، حتى نتمكن من تنفيذها بسرعة من خلال البرنامج:
القائمة الثابتة العامة <Apple> filtergreenapples (قائمة <Apple> Apples) {List <Apple> filterapples = new ArrayList <> () ؛ for (Apple Apple النهائي: التفاح) {if (color.green.equals (Apple.getColor ())) {filterapples.add (Apple) ؛}}}هذا الرمز بسيط ولا شيء يستحق القول. ولكن عندما تصبح احتياجات المستخدم خضراء ، يبدو أن تعديل الكود بسيط ، فهذا ليس أكثر من تغيير أخضر حالة الحكم إلى اللون الأحمر. لكننا بحاجة إلى النظر في قضية أخرى. إذا تغيرت الظروف المتغيرة بشكل متكرر ، فسيتم ذلك؟ إذا كان ذلك مجرد تغيير في اللون ، فيمكننا السماح للمستخدم مباشرة بتمرير شروط الحكم الملونة ، وتغيير معلمات طريقة الحكم "المجموعة التي يتم الحكم عليها واللون المراد ترشيحه". ولكن ماذا لو لم يكن المستخدم يحكم على اللون فحسب ، بل يريد أيضًا الحكم على الوزن والحجم وما إلى ذلك؟ هل تعتقد أنه يمكننا فقط إضافة معلمات مختلفة لإكمال الحكم؟ ولكن هل من الجيد حقًا تمرير المعلمات مثل هذا؟ إذا كان هناك المزيد والمزيد من شروط التصفية ويصبح وضع المركب أكثر تعقيدًا ، هل نحتاج إلى النظر في جميع المواقف ولدينا استراتيجيات مواجهة مقابلة لكل موقف؟ في هذا الوقت ، يمكننا تحديد السلوك ، واستخراج ظروف التصفية ونقلها كمعلمات. في هذا الوقت ، يمكننا تغليف واجهة الحكم:
الواجهة العامة AppleFilter {/*** Filter Abstract ** param Apple* @return*/boolean قبول (Apple Apple) ؛}/*** تغليف المرشحات في واجهة ** @param Apples*param filter* @return*/public static static <Apple> filterapplesBlefilter (list <Apple> apples ، appleter) لـ (Apple Final Apple: Apples) {if (filter.accept (Apple)) {filterapples.add (Apple) ؛}} مرشحات الإرجاع ؛}بعد تجريد السلوك أعلاه ، يمكننا تعيين ظروف المرشح في المكالمة المحددة ونمر الشروط كمعلمات في الطريقة. في هذا الوقت ، نستخدم طريقة الفصل الداخلي المجهول:
Public Static Void Main (String [] args) {List <Apple> Apples = New ArrayList <> () ؛ // Filter Apple List <Sapp> filterapples = filterapplesByApplefilter (Apples ، New Applefilter () {Overridep Boolean قبول (Apple Apple) Apple.getweight ()> 100 ؛}}) ؛}غالبًا ما يتم استخدام هذا التصميم داخل JDK ، مثل java.util.comparator ، java.util.concurrent.callable ، إلخ. عند استخدام هذا النوع من الواجهة ، يمكننا استخدام فئات مجهولة لتحديد منطق التنفيذ المحدد للوظيفة في أماكن المكالمات المحددة. ومع ذلك ، من كتلة الكود أعلاه ، على الرغم من أنها مهووسة للغاية ، إلا أنها ليست موجزة بما فيه الكفاية. في Java8 ، يمكننا تبسيطه من خلال Lambda:
// filter Apple List <Apple> filterapples = filterapplesByAppleFilter (Apples ، (Apple) -> color.equals (Apple.getColor ()) && Apple.GetWeight ()> = 100) ؛ // () -> xxx ()
2. تعريف تعبير Lambda
يمكننا تحديد تعبير Lambda كدالة مجهولة موجزة وقابلة للمرور. بادئ ذي بدء ، نحتاج إلى توضيح أن تعبير Lambda هو في الأساس وظيفة. على الرغم من أنه لا ينتمي إلى فئة معينة ، إلا أنه يحتوي على قائمة معلمات ، وجسم الوظيفة ، ونوع الإرجاع ، والقدرة على رمي الاستثناءات ؛ ثانياً ، إنه مجهول ، ولا يحتوي تعبير Lambda على اسم وظيفة محدد ؛ يمكن تمرير تعبير Lambda مثل المعلمات ، وبالتالي تبسيط كتابة التعليمات البرمجية بشكل كبير. تعريف التنسيق كما يلي:
التنسيق 1: قائمة المعلمات -> التعبير
التنسيق 2: قائمة المعلمات -> {مجموعة التعبير}
تجدر الإشارة إلى أن تعبير Lambda يعني الكلمة الرئيسية لإرجاع ، لذلك في تعبير واحد ، لا نحتاج إلى كتابة الكلمة الرئيسية الإرجاع صراحة ، ولكن عندما يكون التعبير عبارة عن مجموعة من العبارات ، نحتاج إلى إضافة إرجاع بشكل صريح ورفع تعبيرات متعددة مع أقواس Curly {}. دعونا نرى بعض الأمثلة أدناه:
// إرجاع طول السلسلة المحددة ، بيان الإرجاع ضمنيًا (السلسلة) -> s.length () // إرجاع الطريقة غير الموثقة () () -> 42 // تحتوي على خطوط متعددة من التعبير ، محاطة بأقواس مجعد (int x ، int y) -> {int z = x * y ؛ return x + z ؛}3. استخدم تعبيرات Lambda بناءً على واجهات وظيفية
يتطلب استخدام تعبيرات Lambda مساعدة واجهات وظيفية ، مما يعني أنه فقط عندما تظهر الواجهة الوظيفية ، يمكننا تبسيطها مع تعبيرات Lambda.
واجهة وظيفية مخصصة:
يتم تعريف الواجهات الوظيفية على أنها واجهات لها طريقة مجردة واحدة فقط. يتمثل التحسن في تعريف واجهة Java8 في تقديم طرق افتراضية ، حتى نتمكن من توفير تطبيقات افتراضية للطرق في الواجهة. ومع ذلك ، بغض النظر عن عدد الطرق الافتراضية الموجودة ، طالما أن أحدهم وطريقة واحدة فقط مجردة ، فهي واجهة وظيفية ، على النحو التالي (الرجوع إلى AppleFilter أعلاه):
/*** واجهة مرشح Apple*/ @الوظيفية واجهة AppleFilter {/*** مرشح الشرط الملخص ** param Apple* @return*/boolean قبول (Apple Apple) ؛}يحتوي Applefilter فقط على طريقة مجردة (Apple Apple). وفقًا للتعريف ، يمكن اعتباره واجهة وظيفية. عند التعريف ، نضيف @functionalinterface إلى الواجهة لوضع علامة على الواجهة كواجهة وظيفية. ومع ذلك ، هذه الواجهة اختيارية. بعد إضافة هذه الواجهة ، يقيد برنامج التحويل البرمجي الواجهة على طريقة تجريدية فقط ، وإلا سيتم الإبلاغ عن خطأ ، لذلك يوصى بإضافة هذا التعليق التوضيحي إلى الواجهة الوظيفية.
يأتي JDK مع واجهة وظيفية:
JDK هو تعبير lambda مع واجهات وظيفية غنية. فيما يلي أمثلة على استخدام المسند <T> ، المستهلك <T> ، الوظيفة <T ، R> على التوالي.
المسند:
@functionalInterFacepubublic Interface Predicate <T> {/*** يقييم هذا التنبؤ على الوسيطة المحددة. ** param t وسيطة الإدخال* @regude {code true}وظيفة المسند تشبه Applefilter أعلاه. يستخدم الشروط التي حددناها خارجيًا للتحقق من المعلمات الواردة وإرجاع نتيجة التحقق المنطقية. ما يلي يستخدم المسند لتصفية عناصر مجموعة القائمة:
/**** list @param list* param procedicate* param <t>* @return*/public <t> قائمة <T> filter (قائمة <T> قائمة ، مسند <T> مسبق) {list <t> newList = new ArrayList <T> () ؛ for (final t: list) {if (est (test (t)) {newList.Add (t) ؛يستخدم:
demo.filter (list ، (string str) -> null! = str &&! str.isempty ()) ؛
مستهلك
FunctionalInterFacepubublic Interface Consumer <T> {/*** يؤدي هذه العملية على الوسيطة المحددة. ** param t وسيطة الإدخال*/void قبول (t t) ؛}يوفر المستهلك دالة قبول مجردة تتلقى معلمات ولكنها لا تُرجع القيم. ما يلي يستخدم المستهلك لاجتياز المجموعة.
/*** اجتياز المجموعة وأداء السلوك المخصص ** قائمة param* param المستهلك* param <t>*/public <t> مرشح الفراغ (قائمة <T> القائمة ، المستهلك <T> المستهلك) {for (final t: list) {consumer.accept (t) ؛}}}}باستخدام الواجهة الوظيفية أعلاه ، قم بالتكرار من خلال مجموعة السلسلة وطباعة السلاسل غير الفارغة:
demo.filter (list ، (string str) -> {if (stringUtils.isNotBlank (str)) {system.out.println (str) ؛}}) ؛وظيفة
functionalInterfacepublic interface function <t ، r> {/*** تطبق هذه الوظيفة على الوسيطة المحددة. ** param t الوسيطة الوظيفية*return نتيجة الوظيفة*/r تطبيقها (t t) ؛}وظيفة تنفيذ عملية تحويل. الإدخال هو بيانات من النوع T وإرجاع بيانات النوع R. تستخدم الوظيفة التالية لتحويل المجموعة:
Public <T ، R> List <R> filter (قائمة <T> القائمة ، الدالة <T ، R> الدالة) {List <R> newList = New ArrayList <L> () ؛ لـ (Final t: list) {newList.add (function.apply (t)) ؛} إرجاع NewList ؛}آخر:
demo.filter (list ، (string str) -> integer.parseint (str)) ؛
توفر الواجهات الوظيفية أعلاه أيضًا بعض التطبيقات الافتراضية للعمليات المنطقية. لنتحدث عن ذلك لاحقًا عند تقديم الأساليب الافتراضية لواجهة Java8 ~
بعض الأشياء التي يجب الانتباه إليها أثناء الاستخدام:
اكتب الاستدلال:
أثناء عملية الترميز ، قد نتساءل أحيانًا عن الواجهة الوظيفية التي ستتطابق مع رمز الاتصال الخاص بنا. في الواقع ، سيصدر المترجم الأحكام الصحيحة بناءً على المعلمات ، ونوع الإرجاع ، ونوع الاستثناء (إذا كان موجودًا) ، إلخ.
عند الاتصال بطرق محددة ، يمكن حذف نوع المعلمة في بعض الأحيان ، وبالتالي تبسيط الكود:
// filter Apple List <Apple> filterapples = filterapplesByAppleFilter (Apples ، (Apple) -> color.equals (Apple.getColor ()) && Apple.getweight ()> = 100) ؛ // في بعض الحالات ، يمكننا حتى حذف أنواع المعلمة ، وستحكم المتردد بشكل صحيح <Apple> filteraples = filteraples. color.red.equals (Apple.getColor ()) && Apple.GetWeight ()> = 100) ؛
المتغيرات المحلية
جميع الأمثلة فوق تعبيرات Lambda الخاصة بنا تستخدم معلمات الجسم ، يمكننا أيضًا استخدام المتغيرات المحلية في Lambda ، على النحو التالي
int weight = 100 ؛ artial <Apple> filterapples = filterapplesByAppleFilter (Apples ، Apple -> color.equals (Apple.getColor ()) && Apple.getweight ()> = weight) ؛:::
في هذا المثال ، نستخدم الوزن المتغير المحلي في Lambda. ومع ذلك ، يجب أن يتطلب استخدام المتغيرات المحلية في Lambda إعلان المتغير بشكل صريح على أنه نهائي أو نهائي في الواقع. ويرجع ذلك أساسًا إلى تخزين المتغير المحلي على المكدس ، ويتم تشغيل تعبير Lambda في موضوع آخر. عندما يصل عرض مؤشر الترابط إلى المتغير المحلي ، فإن المتغير لديه إمكانية تغيير أو إعادة تدويره ، لذلك لن تكون هناك مشاكل سلامة مؤشر ترابط بعد التعديل مع النهائي.
رابعا. طريقة الاقتباس
يمكن أن يؤدي استخدام مراجع الطريقة إلى جعل الكود أكثر تبسيطًا. في بعض الأحيان يجعل هذا التبسيط الرمز يبدو أكثر سهولة. دعونا نلقي نظرة على مثال:
/* ... حذف عملية التهيئة للتفاح* /// استخدم Lambda Expression Apples.sort ((Apple A ، Apple B) -> float.compare (a.getweight () ، b.Getweight ())) ؛
مراجع الطريقة توصيل طريقة العضوية والطريقة نفسها من خلال :: ، والتي تنقسم بشكل رئيسي إلى ثلاث فئات:
طريقة ثابتة
(args) -> classname.staticmethod (args)
تحويل إلى
ClassName :: StaticMethod
مثال طريقة المعلمة
(args) -> args.instancemethod ()
تحويل إلى
ClassName :: Instancemethod // classname هو نوع args
طريقة المثيل الخارجي
(args) -> ext.instancemethod (args)
تحويل إلى
Ext :: Instancemethod (args)
الرجوع إلى:
http://www.codeceo.com/article/lambda-of-java-8.html
ما سبق هو تعبير Lambda عن ميزة JDK8 الجديدة التي قدمها لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!