
لدي أسئلة حول تعبيرات لامدا و RxJava. تتعلق هذه الأسئلة في الغالب بفهم غير كامل لتعابير لامدا أو RxJava. سأحاول أن أشرح عبارات لامدا بسيطة بقدر الإمكان. RxJava سأصف بشكل منفصل.
تعابير لامدا و RxJava
ما هي تعابير لامدا؟ تعد تعبيرات Lambda "مجرد" طريقة جديدة للقيام بنفس الشيء الذي يمكننا القيام به دائمًا ، ولكن بطريقة جديدة أكثر نظافة وأقل تفصيلاً لاستخدام الطبقات الداخلية المجهولة.
فئة داخلية مجهولة في Java هي فئة غير مسماة ، يجب استخدامها إذا كنت بحاجة إلى تجاوز أساليب الطبقة أو الواجهة. يمكن إنشاء فئة داخلية مجهولة من فئة أو واجهة.
على سبيل المثال:
abstract class Animal { abstract void speak(); } Animal a = new Animal() { void speak() { System.out.println("Woff"); } };
في Android ، نستخدم عادةً فئة داخلية مجهولة كمستمع ، على سبيل المثال ، للأزرار من هذا النوع:
Button btn = findViewById(R.id.button); btn.setOnClickListener( new View.OnClickListener() { @Override public void onClick(final View view) {
دعنا نعود إلى تعابير لامدا. هذا هو الجزء التالي ، وهو جزء من الرمز السابق ، والذي يعتبر فئة داخلية مجهولة.
new View.OnClickListener() { @Override public void onClick(final View view) {
يمكن استخدام تعبيرات Lambda فقط إذا كنت بحاجة إلى تجاوز طريقة واحدة على الأكثر. لحسن الحظ بالنسبة لنا ، تحتوي View.OnClickListener على واحدة فقط. ألق نظرة على الرمز أدناه. أي جزء تعتقد أنه علينا إزالته؟
new View.OnClickListener() { @Override public void onClick(final View view) {
بعد إزالة جميع التعليمات البرمجية تقريبًا ، نحتاج إلى إضافة -> ، كما في الرمز أدناه. يمكن استخدام عرض معلمة الإدخال داخل الوظيفة بنفس الطريقة السابقة.
(view) -> {
في بعض الحالات ، قد تحتاج إلى إضافة نوع إلى معلمة ، إذا لم يتمكن المترجم من تخمينه ، يمكنك القيام بذلك عن طريق إضافته قبل المعلمة:
(View view) -> {
يمكنك أيضًا استخدام رمز متعدد الأسطر:
(view) -> { Intent intent = new Intent(context, AuthActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); view.getContext().startActivity(intent); }
إذا كان لديك واجهة مع طريقة تأخذ معلمتين ...
interface MyInterface { abstract void onMethod(int a, int b); }
... سيبدو تعبير لامدا كما يلي:
(a, b) -> {
إذا كان للطريقة نوع إرجاع ...
interface MySecondInterface { abstract int onSecondMethod(int a, int b); }
... سيبدو تعبير لامدا كما يلي:
(a, b) -> { return a + b; }
ولكن هذا ليس كل شيء ، فهناك بعض الحالات الخاصة التي تجعل الشفرة أصغر. إذا كان نص الطريقة يحتوي على سطر واحد فقط من التعليمات البرمجية ، فيمكنك إزالة الأقواس المتعرجة {} . إذا قمت بإزالة الأقواس المتعرجة ، فستحتاج أيضًا إلى إزالة الفاصلة المنقوطة ، مع ترك ما يلي:
(a, b) -> return a + b
هناك شيء آخر يمكننا القيام به. إذا كان لدينا سطر واحد فقط من التعليمات البرمجية ، فيمكن للمترجم أن يفهم ما إذا كان الجزء الذي تم إرجاعه مطلوبًا أم لا ، لذا يمكننا تركه على النحو التالي:
(a, b) -> a + b
إذا كان لدينا رمز متعدد الأسطر ، فسوف ينزل إلى ما يلي:
(a, b) -> { a+=1; return a + b; }
إذن ماذا فعلنا؟ أخذنا هذا:
new MySecondInterface() { @Override public int onSecondMethod(final int a, final int b) { return a + b; } };
وحولته إلى هذا:
(a, b) -> a + b
لم يبق سوى شيء واحد ، مراجع الطريقة. لنفترض أن لدينا واجهة ، كما كان من قبل ، وطريقة تقبل هذه الواجهة كمعلمة:
public interface Callback { public void onEvent(int event); } public void myMethod(Callback callback){ }
بدون تعبير لامدا ، ستبدو كما يلي:
myMethod(new Callback() { @Override public void onEvent(final int state) { System.out.println(state); } });
بإضافة تعبير لامدا ، كما فعلنا من قبل ، نحصل على ما يلي:
myMethod(state -> System.out.println(state));
لكن هذا ليس كل شيء إذا كان الكود المستخدم عبارة عن سطر واحد وكانت الوظيفة المطلوبة تأخذ معلمة واحدة ، فيمكننا تمرير مرجع الطريقة في هذا النموذج:
myMethod(System.out::println);
سيتم تمرير المعلمة تلقائيًا ، دون الحاجة إلى رمز آخر! حق مدهش؟ أتمنى أن تكون قد تعلمت شيئًا جديدًا!