AMR0T

Members
  • عدد منشوراتي

    9
  • تاريخ الإنضمام

  • تاريخ اخر زياره

السمعه بالموقع

3 Neutral

عن العضو AMR0T

  • الرتبه
    مبدع جديد
  1. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذا الموضوع، سنستعرض الStreams، وهي عبارة عن API جديدة ورائعه تم اضافتها في التحديث الأخير للJava 8. باستخدام الStreams، ستستطيع معالجة بيانات الCollections كأنك تقوم بعمل Query في احد الSQL databases، وذلك بطريقة تعريفية بسيطة دون الحاجة لكتابة Loop في كل مرة تريد معالجة البيانات لتخرج بنتيجة معينة (جمع عناصر الArrayList على سبيل المثال)، وذلك بكتابة سطر برمجي واحد فقط! هناك ميزة أخرى أيضا للStreams، وهي امكانية تفعيل جميع أنوية المعالج لتسريع عملية تنفيذ البرنامج دون الحاجة الى كتابة سطر واحد من كلاس الThreads المزعج! ما هو الStream؟ سنذكر تاليا أهم سمات الStream في الجافا: تسلسل عناصر: الStream هو عبارة عن تسلسل لعناصر يتم استخلاصها من أحد المصادر (Sources) -قد تكون Array أو ArrayList الخ-، حيث يقوم الStream بـ قراءة/معالجة بيانات هذه المصادر عند الحاجة فقط المصادر: قد تكون Collection, Arrays, I/O العمليات: يدعم الStream مجموعة من العمليات (أو methods) على سبيل المثال لا الحصر: filter, map, limit, reduce, find, match تكرارات تلقائية: الStreams تدعم التكرارات التلقائية (Automatic Iterations)، أي كما قلنا سابقا، لن تكتب المزيد من الloops، كل ماعليك فعله هو كتابة سطر واحد باستعمال الStreams والجافا ستقوم بالباقي إنشاء الStream في الجافا 8، هناك طريقتان لإنشاء Stream: ()stream: ستنشئ ستريم تسلسلي مربوط بcollection، ولكن بدون الاستفادة من ميزة تعدد أنوية المعالج في التنفيذ ()parallelStream: ستنشئ ستريم متوازي مربوط بcollection، مستفيدًا من ميزة تعدد أنوية المعالج في التنفيذ مثال: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); أهم ميثودز الStream ()forEach: هذه الميثود تعطيك امكانية المرور بجميع عناصر الستريم للقيام بعملية معينة، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام forEach: Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()map: بهذه الميثود تستخدم لربط كل عنصر بالستريم مع نتيجة خاصة به. في المثال التالي سنقوم بطباعة مربعات ارقام مميزة باستخدام map: List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); ()filter: يتم استخدام هذه الميثود للتخلص من بعض عناصر الستريم بناء على شروط معينة، المثال التالي يقوم بطباعة عدد ال Strings الفارغة: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count(); ()limit: هذه الميثود تستخدم للحد من حجم الستريم بدون أي شروط، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام limit: Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()sorted: يتم استخدام هذه الميثود لترتيب الستريم، الكود التالي يظهر كيف تقوم بطباعة 10 ارقام عشوائية مرتبة: Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println); ( لاحظ كيف أنجزنا المهمة بسطر واحد فقط، تخيل لو أردت أن تقوم بطباعة 10 ارقام عشوائية مرتبة بالطريقة التقليدية! ) Parallel Processing: هذه هي الطريقة الثانية لإنشاء الستريم الموازي (استعمال جميع أنوية المعالج لتنفيذ البرنامج) كما هو مذكور بالأعلى: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.parallelStream().filter(string -> string.isEmpty()).count(); لاحظ أنك تستطيع التبديل بين الStream والparallelStream بسهولة تامة. Collectors: نستخدم الCollectors لجمع نتائج معالجة بيانات الستريم واعادتها على شكل List. List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); في المثال التالي، سنقوم بعمل مقارنة بين الJava 7 والJava 8 في برنامج يقوم بضم الStrings غير الفارغة. import java.util.*; public class Java8StreamTest { public static void main(String[] args) { // Java 7 approach System.out.println("Using Java 7: "); List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); StringBuilder stringBuilder = new StringBuilder(); for (String string: strings) { if (!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(", "); } } String mergedString = stringBuilder.toString(); System.out.println("Merged String: " + mergedString); // Java 8 approach System.out.println("Using Java 8: "); System.out.println("List: " +strings); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); } } وهنا نصل الى ختام موضوعنا، أسأل الله لي ولكم التوفيق والسداد.
  2. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذا الموضوع، سنستعرض الStreams، وهي عبارة عن API جديدة ورائعه تم اضافتها في التحديث الأخير للJava 8. باستخدام الStreams، ستستطيع معالجة بيانات الCollections كأنك تقوم بعمل Query في احد الSQL databases، وذلك بطريقة تعريفية بسيطة دون الحاجة لكتابة Loop في كل مرة تريد معالجة البيانات لتخرج بنتيجة معينة (جمع عناصر الArrayList على سبيل المثال)، وذلك بكتابة سطر برمجي واحد فقط! هناك ميزة أخرى أيضا للStreams، وهي امكانية تفعيل جميع أنوية المعالج لتسريع عملية تنفيذ البرنامج دون الحاجة الى كتابة سطر واحد من كلاس الThreads المزعج! ما هو الStream؟ سنذكر تاليا أهم سمات الStream في الجافا: تسلسل عناصر: الStream هو عبارة عن تسلسل لعناصر يتم استخلاصها من أحد المصادر (Sources) -قد تكون Array أو ArrayList الخ-، حيث يقوم الStream بـ قراءة/معالجة بيانات هذه المصادر عند الحاجة فقط المصادر: قد تكون Collection, Arrays, I/O العمليات: يدعم الStream مجموعة من العمليات (أو methods) على سبيل المثال لا الحصر: filter, map, limit, reduce, find, match تكرارات تلقائية: الStreams تدعم التكرارات التلقائية (Automatic Iterations)، أي كما قلنا سابقا، لن تكتب المزيد من الloops، كل ماعليك فعله هو كتابة سطر واحد باستعمال الStreams والجافا ستقوم بالباقي إنشاء الStream في الجافا 8، هناك طريقتان لإنشاء Stream: ()stream: ستنشئ ستريم تسلسلي مربوط بcollection، ولكن بدون الاستفادة من ميزة تعدد أنوية المعالج في التنفيذ ()parallelStream: ستنشئ ستريم متوازي مربوط بcollection، مستفيدًا من ميزة تعدد أنوية المعالج في التنفيذ مثال: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); أهم ميثودز الStream ()forEach: هذه الميثود تعطيك امكانية المرور بجميع عناصر الستريم للقيام بعملية معينة، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام forEach: Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()map: بهذه الميثود تستخدم لربط كل عنصر بالستريم مع نتيجة خاصة به. في المثال التالي سنقوم بطباعة مربعات ارقام مميزة باستخدام map: List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()); ()filter: يتم استخدام هذه الميثود للتخلص من بعض عناصر الستريم بناء على شروط معينة، المثال التالي يقوم بطباعة عدد ال Strings الفارغة: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count(); ()limit: هذه الميثود تستخدم للحد من حجم الستريم بدون أي شروط، في المثال التالي سنقوم بطباعة 10 ارقام عشوائية باستخدام limit: Random random = new Random(); random.ints().limit(10).forEach(System.out::println); ()sorted: يتم استخدام هذه الميثود لترتيب الستريم، الكود التالي يظهر كيف تقوم بطباعة 10 ارقام عشوائية مرتبة: Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println); ( لاحظ كيف أنجزنا المهمة بسطر واحد فقط، تخيل لو أردت أن تقوم بطباعة 10 ارقام عشوائية مرتبة بالطريقة التقليدية! ) Parallel Processing: هذه هي الطريقة الثانية لإنشاء الستريم الموازي (استعمال جميع أنوية المعالج لتنفيذ البرنامج) كما هو مذكور بالأعلى: List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.parallelStream().filter(string -> string.isEmpty()).count(); لاحظ أنك تستطيع التبديل بين الStream والparallelStream بسهولة تامة. Collectors: نستخدم الCollectors لجمع نتائج معالجة بيانات الستريم واعادتها على شكل List. List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); في المثال التالي، سنقوم بعمل مقارنة بين الJava 7 والJava 8 في برنامج يقوم بضم الStrings غير الفارغة. import java.util.*; public class Java8StreamTest { public static void main(String[] args) { // Java 7 approach System.out.println("Using Java 7: "); List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); StringBuilder stringBuilder = new StringBuilder(); for (String string: strings) { if (!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(", "); } } String mergedString = stringBuilder.toString(); System.out.println("Merged String: " + mergedString); // Java 8 approach System.out.println("Using Java 8: "); System.out.println("List: " +strings); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); } } وهنا نصل الى ختام موضوعنا، أسأل الله لي ولكم التوفيق والسداد. تم ترقية هذا الطرح المميز الى صفحة المقالات
  3. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذا الدرس سنتعرف على احد أهم الأنواع في الSwift الا وهما Structures and Enumerations. أولا: Structures أو struct في Swift او اي لغة برمجة مشابهة، تعتبر الكلاسات حجر الأساس لمبدأ الObject-Oriented Programming. بالإضافة الى الكلاسات، لدينا الStructures التي تعطينا بديل مشابه للكلاسات. الستركتشر مشابه للكلاس، لأنه يمكن أن يحتوي على methods, properties, initializers تماما كما الكلاس، ولكن الفارق الأساسي هو ان الستركتشر يعتبر من نوع Value، والكلاسات تعتبر من نوع Reference. ما معنى Value type و Reference type؟ صورة توضيحية للفرق بين الRegerence والValue جميع الأنواع في الSwift هي اما عبارة عن Value type او Reference type. المتغيرات من نوع القيمة (Value type) -مثل متغيرات الInt والBool-، تقوم بنسخ قيمتها عندما يتم مساواتها بمتغير آخر بينما متغيرات نوع المرجع (Reference type) -مثل أي اوبجكت من كلاس-، تقوم باعارة قيمتها عندما يتم مساواتها بمتغير آخر. لنشرح الفرق بينهم سنطرح هذا المثال البسيط لنوع القيمة: var a: Int var b: Int a=5 b=a a=10 print(a) print(b) في المثال السابق، سيتم طباعة قيمتين مختلفتين لكل من a=10 و b=5، لأن قيمة a نسخت في البداية الى b حتى أصبح كل متغير يحمل قيمة خاصة ومستقلة عن المتغير الآخر، وعند تغيير قيمة a لم تتأثر قيمة b بذلك. ولنوع المرجع لنرى المثال التالي: var a = Car() var b: Car b = a a.startCar() b.printCarStatus() في المثال السابق، اذا طبقنا هذا الكود فسنلاحظ أن متغير السيارة b يعمل بالفعل، أي أن قيمة a اعيرت الى b، بحيث أي تغيير يطرأ على a سيؤثر بb، وأي تغيير يطرأ على b سيؤثر بa. اذا من المهم جدا أن نتذكر بأن الStructures من نوع القيمة (Value type)، بينما الClasses من نوع المرجع (Reference type). اختلاف آخر صغير بين الستركتشرز والكلاسات، أن الproperties في الستركتشر لا يمكن تعديلها بطريقة مباشرة من الميثودز، بل يجب استعمال كلمة mutator لكل ميثود كي نستطيع تعديل الproperties. مثال: struct Circle { var centerX = 0.0, centerY = 0.0, radius = 1.0 mutating func doubleRadius() { radius = radius * 2 } } اذا أردنا مضاعفة قيمة الradius من داخل الفنكشن doubleRadius، فسنضطر لاستخدام كلمة mutator قبل الميثود، دلالة على تغيير المتغير radius بقيمة أخرى دون الحاجة لنسخه. فيما عدا ذلك، فإن الستركتشرز تعتبر مشابهة تماما للكلاسات. ثانيا: Enumerations او enum التعدادات (Enumerations) هي طريقة نستطيع من خلالها أن نجمع العديد من قيم المتغيرات المرتبطة ببعضها. وكما الستركتشرز، فان التعدادات تعتبر من انواع القيمة (Value type). لنفترض بأننا نريد أن نعرف مجموعة الكواكب الشمسية، بدون استخدام التعدادات سنقوم بكتابة كود مشابه للتالي: let mercury = 1 let venus = 2 let earth = 3 ... وبهذه الحالة سنضطر لاضاعة أسطر أخرى للتأكد من الادخال الصحيح، فمثلا لو أدخل احدهم الرقم -1: var currentPlanet = -1 // not a valid planet! فسيكون هناك خطأ أنتاء عمل البرنامج، ان لم نقم بكتابة if-statements مناسبة ولكن في حالة التعدادات، يمكننا كتابتها كالتالي: enum Planet { case mercury = 1 case venus = 2 case earth = 3 case mars = 4 case jupiter = 5 case saturn = 6 case uranus = 7 } او اختصارا: enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune } والآن، ان تم ادخال قيمة غير صحيحة: var currentPlanet = Planet.mercury currentPlanet = -1 // error! فسنتعرف على الخطأ مباشرة. في هذا المثال سنرى امكانية تخزين قيم مختلفة لكل case لاحقا، الآن لننشئ مجموعة الألوان الخاصة بنا: enum Color { case rgb(Int, Int, Int) case argb(Int, Int, Int, Int) case cmyk(Int, Int, Int, Int) case name(String) } عند كتابة الenum بهذه الطريقة، فكأننا نخبر الSwift بأن كل case ستحصل على قيم خاصة بها لاحقا، مثل: var blue = Color.rgb(0, 0, 255) ويمكن استعمال الاختصار التالي عند تغيير قيمة المتغير: var blue = Color.rgb(0, 0, 255) blue = .argb(100, 0, 0, 255) blue = .name("blue") فبعد المساواة الأولى، أصبح من المعروف أن المتغير blue لن يخرج عن أحد خيارات المتعدد Color. وهنا نصل الى ختام موضوعنا، تقبل الله منا ومنكم صالح الأعمال والسلام عليكم ورحمة الله
  4. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته في هذا الدرس سنتعرف على احد أهم الأنواع في الSwift الا وهما Structures and Enumerations. أولا: Structures أو struct في Swift او اي لغة برمجة مشابهة، تعتبر الكلاسات حجر الأساس لمبدأ الObject-Oriented Programming. بالإضافة الى الكلاسات، لدينا الStructures التي تعطينا بديل مشابه للكلاسات. الستركتشر مشابه للكلاس، لأنه يمكن أن يحتوي على methods, properties, initializers تماما كما الكلاس، ولكن الفارق الأساسي هو ان الستركتشر يعتبر من نوع Value، والكلاسات تعتبر من نوع Reference. ما معنى Value type و Reference type؟ صورة توضيحية للفرق بين الRegerence والValue جميع الأنواع في الSwift هي اما عبارة عن Value type او Reference type. المتغيرات من نوع القيمة (Value type) -مثل متغيرات الInt والBool-، تقوم بنسخ قيمتها عندما يتم مساواتها بمتغير آخر بينما متغيرات نوع المرجع (Reference type) -مثل أي اوبجكت من كلاس-، تقوم باعارة قيمتها عندما يتم مساواتها بمتغير آخر. لنشرح الفرق بينهم سنطرح هذا المثال البسيط لنوع القيمة: var a: Int var b: Int a=5 b=a a=10 print(a) print(b) في المثال السابق، سيتم طباعة قيمتين مختلفتين لكل من a=10 و b=5، لأن قيمة a نسخت في البداية الى b حتى أصبح كل متغير يحمل قيمة خاصة ومستقلة عن المتغير الآخر، وعند تغيير قيمة a لم تتأثر قيمة b بذلك. ولنوع المرجع لنرى المثال التالي: var a = Car() var b: Car b = a a.startCar() b.printCarStatus() في المثال السابق، اذا طبقنا هذا الكود فسنلاحظ أن متغير السيارة b يعمل بالفعل، أي أن قيمة a اعيرت الى b، بحيث أي تغيير يطرأ على a سيؤثر بb، وأي تغيير يطرأ على b سيؤثر بa. اذا من المهم جدا أن نتذكر بأن الStructures من نوع القيمة (Value type)، بينما الClasses من نوع المرجع (Reference type). اختلاف آخر صغير بين الستركتشرز والكلاسات، أن الproperties في الستركتشر لا يمكن تعديلها بطريقة مباشرة من الميثودز، بل يجب استعمال كلمة mutator لكل ميثود كي نستطيع تعديل الproperties. مثال: struct Circle { var centerX = 0.0, centerY = 0.0, radius = 1.0 mutating func doubleRadius() { radius = radius * 2 } } اذا أردنا مضاعفة قيمة الradius من داخل الفنكشن doubleRadius، فسنضطر لاستخدام كلمة mutator قبل الميثود، دلالة على تغيير المتغير radius بقيمة أخرى دون الحاجة لنسخه. فيما عدا ذلك، فإن الستركتشرز تعتبر مشابهة تماما للكلاسات. ثانيا: Enumerations او enum التعدادات (Enumerations) هي طريقة نستطيع من خلالها أن نجمع العديد من قيم المتغيرات المرتبطة ببعضها. وكما الستركتشرز، فان التعدادات تعتبر من انواع القيمة (Value type). لنفترض بأننا نريد أن نعرف مجموعة الكواكب الشمسية، بدون استخدام التعدادات سنقوم بكتابة كود مشابه للتالي: let mercury = 1 let venus = 2 let earth = 3 ... وبهذه الحالة سنضطر لاضاعة أسطر أخرى للتأكد من الادخال الصحيح، فمثلا لو أدخل احدهم الرقم -1: var currentPlanet = -1 // not a valid planet! فسيكون هناك خطأ أنتاء عمل البرنامج، ان لم نقم بكتابة if-statements مناسبة ولكن في حالة التعدادات، يمكننا كتابتها كالتالي: enum Planet { case mercury = 1 case venus = 2 case earth = 3 case mars = 4 case jupiter = 5 case saturn = 6 case uranus = 7 } او اختصارا: enum Planet { case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune } والآن، ان تم ادخال قيمة غير صحيحة: var currentPlanet = Planet.mercury currentPlanet = -1 // error! فسنتعرف على الخطأ مباشرة. في هذا المثال سنرى امكانية تخزين قيم مختلفة لكل case لاحقا، الآن لننشئ مجموعة الألوان الخاصة بنا: enum Color { case rgb(Int, Int, Int) case argb(Int, Int, Int, Int) case cmyk(Int, Int, Int, Int) case name(String) } عند كتابة الenum بهذه الطريقة، فكأننا نخبر الSwift بأن كل case ستحصل على قيم خاصة بها لاحقا، مثل: var blue = Color.rgb(0, 0, 255) ويمكن استعمال الاختصار التالي عند تغيير قيمة المتغير: var blue = Color.rgb(0, 0, 255) blue = .argb(100, 0, 0, 255) blue = .name("blue") فبعد المساواة الأولى، أصبح من المعروف أن المتغير blue لن يخرج عن أحد خيارات المتعدد Color. وهنا نصل الى ختام موضوعنا، تقبل الله منا ومنكم صالح الأعمال والسلام عليكم ورحمة الله تم ترقية هذا الطرح المميز الى صفحة المقالات
  5. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته، سنتحدث في هذا الموضوع عن مفهوم الAbstract عامة وبالتحديد في لغة الJava، وكيفية استخدامه وتطبيقه مع امثلة توضيحية ماهو الAbstraction؟ اذا بحثنا في القاموس عن معنى كلمة Abstract (تجريد)، فسنجد انها تعني [ خاصية التعامل مع الفكرة لا الحدث ]. بمعنى اهمال التفاصيل الغير لازمة واستبدالها بما هو مهم وواضح. مثال على ذلك: عندما تحاول ان ترسل ايميل الى شخص ما، فانك لن تهتم بالتفاصيل الصغيرة مثل مالذي يحدث بالضبط عندما تضغط على زر ارسال او البروتوكول المستخدم لنقل الرسالة. كل ما تريد عمله هو ان تكتب عنوان الرسالة والمحتوى ومستقبل الرسالة وترسلها. نفس الشيء ينطبق في مفاهيم ال Object-Oriented. في الabstraction نهدف الى اخفاء تفاصيل الimplementation عن المستخدم، بمعنى اخر، المستخدم سيهتم بما الغرض من الobject بدلا عن كيفية قيامه به. في الجافا، يمكننا تطبيق هذا المفهوم عن طريق انشاء abstract class او abstract interface، (عكسها concrete class او normal class) Abstract Classes الكلاس الذي يحتوي على كلمة abstract في تعريفه يعتبر abstract class، وسيتبع القوانين التالية: من الممكن للAbstract class أن يحتوي على abstract methods (ليس اجباريا)، وهي الميثودز التي لا تحتوي على تعريف مثل ( ;()public abstract void get ) ولكن، اذا احتوى الكلاس على abstract method، فيجب تعريفه ك abstract class اذا تم تعريف الكلاس ك abstract، فلا يمكن انشاء objects منه لتستخدم ال abstract class وخصائصه، يجب عليك ان ترثه (inherit it) من كلاس آخر، ويجب عليك اعادة تعريف كل ال abstract methods مثال: سننشئ abstract class باضافة الكلمة abstract الى تعريف الكلاس: public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } } لاحظ ان الabstract class السابق لا يختلف ابدا عن الكلاس العادي، فهو يحتوي على attributes, constructor, normal methods. الفرق الوحيد هو كلمة abstract بالتعريف الآن لنحاول انشاء اوبجكت من الكلاس السابق: public class AbstractDemo { public static void main(String [] args) { Employee e = new Employee("George W.", "Houston, TX", 43); e.computePay(); } } عند تشغيل البرنامج سنحصل على الخطأ التالي: Employee.java:46: Employee is abstract; cannot be instantiated Employee e = new Employee("George W.", "Houston, TX", 43); ^ 1 error لأنه لا يمكن انشاء اوبجكت من abstract class حتى وان احتوى على constructor. Inheriting Abstract Classes نستطيع اعادة استخدام خصائص وميثودز الabstract class تماما كأي كلاس آخر عن طريق وراثته (extends): public class Salary extends Employee { private double salary; // Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } هنا لا يمكننا انشاء اوبجكت من كلاس Employee، ولكن يمكننا انشاء اوبجكت من كلاس Salary واستخدام جميع خصائص وميثودز كلاس Employee: public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } } والOutput سيكون كالتالي: Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0 Call mailCheck using Employee reference-- Within mailCheck of Salary class Mailing check to John Adams with salary 2400.0 Abstract Methods اذا اردت انشاء ميثود ولكنك تريد تعريفها بالكلاس الإبن (Inheriting class)، يمكنك استخدام كلمة abstract في تعريف الميثود، مثال: public abstract class Employee { private String name; private String address; private int number; public abstract double computePay(); } تعريف الميثود (مثل ()computePay) ك abstract method له آثار يجب الانتباه لها: الكلاس الذي يحتويها يجب أن يكون abstract الكلاس الذي يرث الكلاس الذي يحتويها يجب أن يعيد تعريفها مثال، كلاس Salary سيرث كلاس Employee السابق: public class Salary extends Employee { private double salary; // Annual salary public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } نلاحظ أن الميثود ()computePay تمت اعادة تعريفها لتحصل على implementation جديد خاص بكلاس Salary هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
  6. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته، سنتحدث في هذا الموضوع عن مفهوم الAbstract عامة وبالتحديد في لغة الJava، وكيفية استخدامه وتطبيقه مع امثلة توضيحية ماهو الAbstraction؟ اذا بحثنا في القاموس عن معنى كلمة Abstract (تجريد)، فسنجد انها تعني [ خاصية التعامل مع الفكرة لا الحدث ]. بمعنى اهمال التفاصيل الغير لازمة واستبدالها بما هو مهم وواضح. مثال على ذلك: عندما تحاول ان ترسل ايميل الى شخص ما، فانك لن تهتم بالتفاصيل الصغيرة مثل مالذي يحدث بالضبط عندما تضغط على زر ارسال او البروتوكول المستخدم لنقل الرسالة. كل ما تريد عمله هو ان تكتب عنوان الرسالة والمحتوى ومستقبل الرسالة وترسلها. نفس الشيء ينطبق في مفاهيم ال Object-Oriented. في الabstraction نهدف الى اخفاء تفاصيل الimplementation عن المستخدم، بمعنى اخر، المستخدم سيهتم بما الغرض من الobject بدلا عن كيفية قيامه به. في الجافا، يمكننا تطبيق هذا المفهوم عن طريق انشاء abstract class او abstract interface، (عكسها concrete class او normal class) Abstract Classes الكلاس الذي يحتوي على كلمة abstract في تعريفه يعتبر abstract class، وسيتبع القوانين التالية: من الممكن للAbstract class أن يحتوي على abstract methods (ليس اجباريا)، وهي الميثودز التي لا تحتوي على تعريف مثل ( ;()public abstract void get ) ولكن، اذا احتوى الكلاس على abstract method، فيجب تعريفه ك abstract class اذا تم تعريف الكلاس ك abstract، فلا يمكن انشاء objects منه لتستخدم ال abstract class وخصائصه، يجب عليك ان ترثه (inherit it) من كلاس آخر، ويجب عليك اعادة تعريف كل ال abstract methods مثال: سننشئ abstract class باضافة الكلمة abstract الى تعريف الكلاس: public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } } لاحظ ان الabstract class السابق لا يختلف ابدا عن الكلاس العادي، فهو يحتوي على attributes, constructor, normal methods. الفرق الوحيد هو كلمة abstract بالتعريف الآن لنحاول انشاء اوبجكت من الكلاس السابق: public class AbstractDemo { public static void main(String [] args) { Employee e = new Employee("George W.", "Houston, TX", 43); e.computePay(); } } عند تشغيل البرنامج سنحصل على الخطأ التالي: Employee.java:46: Employee is abstract; cannot be instantiated Employee e = new Employee("George W.", "Houston, TX", 43); ^ 1 error لأنه لا يمكن انشاء اوبجكت من abstract class حتى وان احتوى على constructor. Inheriting Abstract Classes نستطيع اعادة استخدام خصائص وميثودز الabstract class تماما كأي كلاس آخر عن طريق وراثته (extends): public class Salary extends Employee { private double salary; // Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } هنا لا يمكننا انشاء اوبجكت من كلاس Employee، ولكن يمكننا انشاء اوبجكت من كلاس Salary واستخدام جميع خصائص وميثودز كلاس Employee: public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } } والOutput سيكون كالتالي: Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0 Call mailCheck using Employee reference-- Within mailCheck of Salary class Mailing check to John Adams with salary 2400.0 Abstract Methods اذا اردت انشاء ميثود ولكنك تريد تعريفها بالكلاس الإبن (Inheriting class)، يمكنك استخدام كلمة abstract في تعريف الميثود، مثال: public abstract class Employee { private String name; private String address; private int number; public abstract double computePay(); } تعريف الميثود (مثل ()computePay) ك abstract method له آثار يجب الانتباه لها: الكلاس الذي يحتويها يجب أن يكون abstract الكلاس الذي يرث الكلاس الذي يحتويها يجب أن يعيد تعريفها مثال، كلاس Salary سيرث كلاس Employee السابق: public class Salary extends Employee { private double salary; // Annual salary public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } } نلاحظ أن الميثود ()computePay تمت اعادة تعريفها لتحصل على implementation جديد خاص بكلاس Salary هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
  7. السلام عليكم ورحمة الله وبركاته، هذا الدرس البسيط سيشرح باذن الله مفهوم الOverloading وطريقة تطبيقه على لغة الJava ماهو الOverloading؟ هي ميزة تقدمها العديد من لغات البرمجة، تتيح للمبرمج كتابة اثنين او اكثر من الmethods المتكررة (تحمل نفس الاسم) ولكن تختلف بخصائصها. كيف نفرق بين هذه الmethods المتشابهة؟ صحيح ان الOverloaded methods تتشابه في الاسم، ولكنها يجب أن تختلف في أحد أو كل ما يلي: عدد الParameters نوع الParameters ترتيب الParameters أمثلة للMethod overloading: كما ذكرنا بالأعلى، فإن الOverloaded methods يجب ان تختلف في الArgument list وسنرى الآن مثال لكل حالة ممكنة للOverloading. مثال 1: اختلاف عدد الParameters class DisplayOverloading { public void disp(char c) { System.out.println(c); } public void disp(char c, int num) { System.out.println(c + " "+num); } } class Sample { public static void main(String args[]) { DisplayOverloading obj = new DisplayOverloading(); obj.disp('a'); obj.disp('a',10); } } Output: a a 10 في المثال السابق، قمنا بكتابة الميثود ()disp مرتين، مرة باستخدام Parameter واحد ومرة باستخدام اثنين. نلاحظ ان الcompiler ذكي كفاية ليربط لنا كل استدعاء بالميثود المناسبة له حسب الArgument list المستخدمة. مثال 2: اختلاف نوع الParameters class DisplayOverloading2 { public void disp(char c) { System.out.println(c); } public void disp(int c) { System.out.println(c ); } } class Sample2 { public static void main(String args[]) { DisplayOverloading2 obj = new DisplayOverloading2(); obj.disp('a'); obj.disp(5); } } Output: a 5 كما المثال السابق، نلاحظ هنا ان الميثود ()disp كتبت مرتين، مرة مع Parameter من نوع char ومرة من نوع int. مثال 3: اختلاف ترتيب الParameters في هذا المثال، قمنا بتغيير ترتيب الParameters لكتابة اكثر من نسخة من الميثود ()disp، في المرة الأولى كانت تحتوي على (char, int) وفي الثانية اصبحت (int, char). class DisplayOverloading3 { public void disp(char c, int num) { System.out.println("I’m the first definition of method disp"); } public void disp(int num, char c) { System.out.println("I’m the second definition of method disp" ); } } class Sample3 { public static void main(String args[]) { DisplayOverloading3 obj = new DisplayOverloading3(); obj.disp('x', 51 ); obj.disp(52, 'y'); } } Output: I’m the first definition of method disp I’m the second definition of method disp لنرى امثلة على طرق overload خاطئة: الحالة 1: int mymethod(int a, int b, float c) int mymethod(int var1, int var2, float var3) النتيجة: خطأ في الCompilation، كلا الميثودين يحملان نفس عدد ونوع وترتيب الParameters. الحالة 2: int mymethod(int a, int b) float mymethod(int var1, int var2) النتيجة: خطأ في الCompilation، اختلاف الreturn type للميثودين لا يهم في الoverloading. هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
  8. السلام عليكم ورحمة الله وبركاته، هذا الدرس البسيط سيشرح باذن الله مفهوم الOverloading وطريقة تطبيقه على لغة الJava ماهو الOverloading؟ هي ميزة تقدمها العديد من لغات البرمجة، تتيح للمبرمج كتابة اثنين او اكثر من الmethods المتكررة (تحمل نفس الاسم) ولكن تختلف بخصائصها. كيف نفرق بين هذه الmethods المتشابهة؟ صحيح ان الOverloaded methods تتشابه في الاسم، ولكنها يجب أن تختلف في أحد أو كل ما يلي: عدد الParameters نوع الParameters ترتيب الParameters أمثلة للMethod overloading: كما ذكرنا بالأعلى، فإن الOverloaded methods يجب ان تختلف في الArgument list وسنرى الآن مثال لكل حالة ممكنة للOverloading. مثال 1: اختلاف عدد الParameters class DisplayOverloading { public void disp(char c) { System.out.println(c); } public void disp(char c, int num) { System.out.println(c + " "+num); } } class Sample { public static void main(String args[]) { DisplayOverloading obj = new DisplayOverloading(); obj.disp('a'); obj.disp('a',10); } } Output: a a 10 في المثال السابق، قمنا بكتابة الميثود ()disp مرتين، مرة باستخدام Parameter واحد ومرة باستخدام اثنين. نلاحظ ان الcompiler ذكي كفاية ليربط لنا كل استدعاء بالميثود المناسبة له حسب الArgument list المستخدمة. مثال 2: اختلاف نوع الParameters class DisplayOverloading2 { public void disp(char c) { System.out.println(c); } public void disp(int c) { System.out.println(c ); } } class Sample2 { public static void main(String args[]) { DisplayOverloading2 obj = new DisplayOverloading2(); obj.disp('a'); obj.disp(5); } } Output: a 5 كما المثال السابق، نلاحظ هنا ان الميثود ()disp كتبت مرتين، مرة مع Parameter من نوع char ومرة من نوع int. مثال 3: اختلاف ترتيب الParameters في هذا المثال، قمنا بتغيير ترتيب الParameters لكتابة اكثر من نسخة من الميثود ()disp، في المرة الأولى كانت تحتوي على (char, int) وفي الثانية اصبحت (int, char). class DisplayOverloading3 { public void disp(char c, int num) { System.out.println("I’m the first definition of method disp"); } public void disp(int num, char c) { System.out.println("I’m the second definition of method disp" ); } } class Sample3 { public static void main(String args[]) { DisplayOverloading3 obj = new DisplayOverloading3(); obj.disp('x', 51 ); obj.disp(52, 'y'); } } Output: I’m the first definition of method disp I’m the second definition of method disp لنرى امثلة على طرق overload خاطئة: الحالة 1: int mymethod(int a, int b, float c) int mymethod(int var1, int var2, float var3) النتيجة: خطأ في الCompilation، كلا الميثودين يحملان نفس عدد ونوع وترتيب الParameters. الحالة 2: int mymethod(int a, int b) float mymethod(int var1, int var2) النتيجة: خطأ في الCompilation، اختلاف الreturn type للميثودين لا يهم في الoverloading. هنا نصل الى نهاية موضوعنا، أتمنى لي ولكم التوفيق والسداد.
  9. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته سنتطرق في هذا الموضوع للGenerics (الميثودز العامة)، مقدمة عن ماهي، ما فائدتها، وكيفية استخدامها بالجافا. مقدمة في أي مشروع او برنامج تعمل عليه بالجافا، ستواجه مشاكل في الcompiling وستواجه الكثير من الexceptions. لذلك من مهام المسؤولين عن لغة الجافا أن يساعدوا المطورين في مواجهة هذه الأخطاء والتقليل منها بقدر المستطاع. أحد أهم ما قدم في تحديث الJava 1.5 كان هو الGenerics. طريقة جديدة لتجنب مشاكل قد تواجهك في تطويرك لمشروعك. فائدتها ماهي هذه المشاكل التي قد تواجهك؟ أكبر مشكلة أتت هذه الGenerics لحلها هي الأنواع المستخدمة في المجموعات (Collections)، كالArrayList, LinkedLists الخ.. المشكلة تكمن (ما قبل Java 1.5) في النوع المستخدم لعناصر الCollection غير قابل للتحديد من قبل الكلاس، لذلك عندما يأتي المستخدم وينشئ اوبجكت من هذا الكلاس ويستخدم الميثودز الخاصة به، قد يستخدم cast خاطئ لعنصر في collection معينة، فمثلا قد يعمل كاست لعنصر (Integer) ك(String) مثلا: static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (((String) i.next()).length() == 4) i.remove(); } في المثال السابق، الميثود expurgate ستفترض دائما أن العناصر المقروءة من المجموعة c هي Strings. بالتالي في حالة أن اخطأ المستخدم بادخال مجموعة تحتوي على عناصر من نوع آخر سنواجه Casting exceptions. سنعدل المثال السابق باستخدام الgenerics لنرى كيف نتفادى مشاكل الcasting: static void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove(); } لاحظ تحديد نوع العناصر في الانبوت لتكون من نوع String، ولاحظ أيضا عدم الحاجة للCast داخل اللوب، وبذلك نلغي احتمالية حدوث Cast exceptions. سنتحدث عن الSyntax وأنواع الجينات لاحقا. لكن لنخلص أهم فوائد الGenerics أولا: مساعدة الCompiler في تحديد الأخطاء وقت الCompilation التخلص من الCasts مساعدة المطورين على كتابة ميثودز عامة، وعدم الحاجة لكتابة أكثر من ميثود لاستقبال أكثر من نوع من الparameters. طريقة استخدامها لاشك أنك لاحظت أن الGenerics تستعمل نوع خاص من الأقواس <> (الدايموند)، هذا صحيح. يجب استعمال هذه الأقواس عند الرغبة باستخدام الGenerics في كتابة الكلاسات وعند الرغبة بانشاء Objects منها. لنأخذ مثال كلاس الArrayList الموجود في مكاتب الجافا الافتراضية، مكتوب بالشكل التالي: public class ArrayList<E> implements List<E> .... { // Constructor public ArraList() { ...... } // Public methods public boolean add(E e) { ...... } public void add(int index, E element) { ...... } public boolean addAll(int index, Collection<? extends E> c) public abstract E get(int index) { ...... } public E remove(int index) ....... } نلاحظ استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين لعناصر الArrayList وترك الخيار للمستخدم. لإنشاء اوبجكت ArrayList: ArrayList<Integer> lst1 = new ArrayList<Integer>(); // E substituted with Integer lst1.add(0, new Integer(88)); lst1.get(0); ArrayList<String> lst2 = new ArrayList<String>(); // E substituted with String lst2.add(0, "Hello"); lst2.get(0); قمنا هنا بانشاء اوبجكتين من الArrayList الأول بعناصر من نوع Integer والثاني بعناصر من نوع String، وذلك باستخدام الكلاس والميثودز نفسها. إذا اردت انشاء كلاس خاص فيك وربط الاوبجكت بنوع عام (وترك التخصيص للمستخدم) يمكنك عمل التالي: public class GenericBox<E> { // Private variable private E content; // Constructor public GenericBox(E content) { this.content = content; } public E getContent() { return content; } public void setContent(E content) { this.content = content; } public String toString() { return content + " (" + content.getClass() + ")"; } } نلاحظ مرة أخرى استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين وترك الخيار للمستخدم. لاحظ في ميثود الtoString() قمنا باستدعاء الكلاس الخاص بالGeneric (أيا كان) لطباعته. لإنشاء أوبجكت من الكلاس السابق: public class TestGenericBox { public static void main(String[] args) { GenericBox<String> box1 = new GenericBox<String>("Hello"); String str = box1.getContent(); System.out.println(box1); GenericBox<Integer> box2 = new GenericBox<Integer>(123); // autobox int to Integer int i = box2.getContent(); System.out.println(box2); GenericBox<Double> box3 = new GenericBox<Double>(55.66); // autobox double to Double double d = box3.getContent(); System.out.println(box3); } } قمنا بالكود السابق انشاء 3 اوبجكتات من الكلاس GenericBox بانواع مختلفة، وأيضا باستخدام الكلاس والمثودز نفسها . أنواعها للGenerics أنواع عديدة أهمها: <Element - <E تستخدم كثيرا في مكتبات الجافا الافتراضية <Type - <T مقاربة للنوع الأول وأكثر الأنواع استخداما من قبل المطورين <Key & Value - <K, V للأنواع المتعددة (مفتاح وقيمة) ... مثال على استخدام Generic الأنواع المتعددة: public interface Pair<K, V> { public K getKey(); public V getValue(); } public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } ولإنشاء اوبجكت من الPair class: Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world"); اختصار يمكن الإستغناء عن تحديد انواع العناصر عند استدعاء الConstructor والاكتفاء بتحديدها عند التعريف، حيث يمكن للCompiler ان يربطهما. OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8); OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world"); المراجع Oracle : The Java™ Tutorials: Generics (Updated)s ntu : Java Programming Tutorial: Generics
  10. بسم الله الرحمن الرحيم السلام عليكم ورحمة الله وبركاته سنتطرق في هذا الموضوع للGenerics (الميثودز العامة)، مقدمة عن ماهي، ما فائدتها، وكيفية استخدامها بالجافا. مقدمة في أي مشروع او برنامج تعمل عليه بالجافا، ستواجه مشاكل في الcompiling وستواجه الكثير من الexceptions. لذلك من مهام المسؤولين عن لغة الجافا أن يساعدوا المطورين في مواجهة هذه الأخطاء والتقليل منها بقدر المستطاع. أحد أهم ما قدم في تحديث الJava 1.5 كان هو الGenerics. طريقة جديدة لتجنب مشاكل قد تواجهك في تطويرك لمشروعك. فائدتها ماهي هذه المشاكل التي قد تواجهك؟ أكبر مشكلة أتت هذه الGenerics لحلها هي الأنواع المستخدمة في المجموعات (Collections)، كالArrayList, LinkedLists الخ.. المشكلة تكمن (ما قبل Java 1.5) في النوع المستخدم لعناصر الCollection غير قابل للتحديد من قبل الكلاس، لذلك عندما يأتي المستخدم وينشئ اوبجكت من هذا الكلاس ويستخدم الميثودز الخاصة به، قد يستخدم cast خاطئ لعنصر في collection معينة، فمثلا قد يعمل كاست لعنصر (Integer) ك(String) مثلا: static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (((String) i.next()).length() == 4) i.remove(); } في المثال السابق، الميثود expurgate ستفترض دائما أن العناصر المقروءة من المجموعة c هي Strings. بالتالي في حالة أن اخطأ المستخدم بادخال مجموعة تحتوي على عناصر من نوع آخر سنواجه Casting exceptions. سنعدل المثال السابق باستخدام الgenerics لنرى كيف نتفادى مشاكل الcasting: static void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove(); } لاحظ تحديد نوع العناصر في الانبوت لتكون من نوع String، ولاحظ أيضا عدم الحاجة للCast داخل اللوب، وبذلك نلغي احتمالية حدوث Cast exceptions. سنتحدث عن الSyntax وأنواع الجينات لاحقا. لكن لنخلص أهم فوائد الGenerics أولا: مساعدة الCompiler في تحديد الأخطاء وقت الCompilation التخلص من الCasts مساعدة المطورين على كتابة ميثودز عامة، وعدم الحاجة لكتابة أكثر من ميثود لاستقبال أكثر من نوع من الparameters. طريقة استخدامها لاشك أنك لاحظت أن الGenerics تستعمل نوع خاص من الأقواس <> (الدايموند)، هذا صحيح. يجب استعمال هذه الأقواس عند الرغبة باستخدام الGenerics في كتابة الكلاسات وعند الرغبة بانشاء Objects منها. لنأخذ مثال كلاس الArrayList الموجود في مكاتب الجافا الافتراضية، مكتوب بالشكل التالي: public class ArrayList<E> implements List<E> .... { // Constructor public ArraList() { ...... } // Public methods public boolean add(E e) { ...... } public void add(int index, E element) { ...... } public boolean addAll(int index, Collection<? extends E> c) public abstract E get(int index) { ...... } public E remove(int index) ....... } نلاحظ استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين لعناصر الArrayList وترك الخيار للمستخدم. لإنشاء اوبجكت ArrayList: ArrayList<Integer> lst1 = new ArrayList<Integer>(); // E substituted with Integer lst1.add(0, new Integer(88)); lst1.get(0); ArrayList<String> lst2 = new ArrayList<String>(); // E substituted with String lst2.add(0, "Hello"); lst2.get(0); قمنا هنا بانشاء اوبجكتين من الArrayList الأول بعناصر من نوع Integer والثاني بعناصر من نوع String، وذلك باستخدام الكلاس والميثودز نفسها. إذا اردت انشاء كلاس خاص فيك وربط الاوبجكت بنوع عام (وترك التخصيص للمستخدم) يمكنك عمل التالي: public class GenericBox<E> { // Private variable private E content; // Constructor public GenericBox(E content) { this.content = content; } public E getContent() { return content; } public void setContent(E content) { this.content = content; } public String toString() { return content + " (" + content.getClass() + ")"; } } نلاحظ مرة أخرى استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين وترك الخيار للمستخدم. لاحظ في ميثود الtoString() قمنا باستدعاء الكلاس الخاص بالGeneric (أيا كان) لطباعته. لإنشاء أوبجكت من الكلاس السابق: public class TestGenericBox { public static void main(String[] args) { GenericBox<String> box1 = new GenericBox<String>("Hello"); String str = box1.getContent(); System.out.println(box1); GenericBox<Integer> box2 = new GenericBox<Integer>(123); // autobox int to Integer int i = box2.getContent(); System.out.println(box2); GenericBox<Double> box3 = new GenericBox<Double>(55.66); // autobox double to Double double d = box3.getContent(); System.out.println(box3); } } قمنا بالكود السابق انشاء 3 اوبجكتات من الكلاس GenericBox بانواع مختلفة، وأيضا باستخدام الكلاس والمثودز نفسها . أنواعها للGenerics أنواع عديدة أهمها: <Element - <E تستخدم كثيرا في مكتبات الجافا الافتراضية <Type - <T مقاربة للنوع الأول وأكثر الأنواع استخداما من قبل المطورين <Key & Value - <K, V للأنواع المتعددة (مفتاح وقيمة) ... مثال على استخدام Generic الأنواع المتعددة: public interface Pair<K, V> { public K getKey(); public V getValue(); } public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } ولإنشاء اوبجكت من الPair class: Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world"); اختصار يمكن الإستغناء عن تحديد انواع العناصر عند استدعاء الConstructor والاكتفاء بتحديدها عند التعريف، حيث يمكن للCompiler ان يربطهما. OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8); OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world"); المراجع Oracle : The Java™ Tutorials: Generics (Updated)s ntu : Java Programming Tutorial: Generics
  11. السلام عليكم ورحمة الله وبركاته في هذه المقاله سنناقش انواع الInner classes في الجافا في الجافا، كتابة class داخل class آخر مسموح، الكلاس الداخلي يسمى Nested class والخارجي يسمى Outer class. كمثال على الNested class: class Outer { class Nested { } } يمكن تقسيم الNested classes الى نوعين: Non-static nested classes Static nested classes نبدأ أولا بالInner classes Inner Classes (Non-static Nested Classes) يمكن التفكير ب الInner classes كحماية اضافية للكلاس الداخلي. من المعروف أن الكلاس لا يمكن ربطه باحد الaccess modifiers مثل (public, private, etc...)، ولكن يمكننا فعل ذلك اذا كان Inner class للInner classes ثلاثة أنواع: Inner classes Method-local inner classes Anonymous inner classes 1- Inner classes انشاء Inner class بسيط جدا، كل ما عليك فعله هو أن تعرف كلاس بداخل كلاس آخر كما رأينا بالأعلى سنعرف Private inner class بالمثال التالي: class Outer { int num; // inner class private class Inner { public void print() { System.out.println("This is an inner class"); } } // Accessing he inner class from the method within void display_Inner() { Inner inner = new Inner(); inner.print(); } } public class My_class { public static void main(String args[]) { // Instantiating the outer class Outer outer = new Outer(); // Accessing the display_Inner() method. outer.display_Inner(); } } Output: This is an inner class. في هذا المثال استعملنا method اضافية [()display_Inner] لعمل object من الprivate inner class ومن ثم استدعاء الميثود بداخله. باختصار، الطريقة الصحيحة لعمل Instantiating للInner class كالتالي: Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); 2- Method-local Inner Classes في الجافا، يمكننا أيضا ان نعرف كلاس داخل ميثود معينة، ولكن هذا الكلاس لا يمكن تعريفه أو استخدامه الا داخل نفس الميثود. المثال التالي يشرح كيفية استخدام الmethod-local inner class: public class Outer { // instance method of the outer class void my_Method() { int num = 23; // method-local inner class class MethodInner { public void print() { System.out.println("This is method inner class "+num); } } // end of inner class // Accessing the inner class within the same scope MethodInner inner = new MethodInner(); inner.print(); } public static void main(String args[]) { Outerclass outer = new Outerclass(); outer.my_Method(); } } Output: This is method inner class 23 3- Anonymous Inner Class هو كلاس يتم انشاؤه بدون اسم محدد له (Anonymous). عموما نستخدم هذا النوع من الكلاسات عندما نريد أن نعمل override لميثود في كلاس او انترفيس. مثال لكيفية انشاء Anonymous inner class: AnonymousInner an_inner = new AnonymousInner() { public void my_method() { ........ ........ } }; البرنامج التالي يوضح استخدام الAnonymous inner class لعمل override لميثود موجودة بabstract class: abstract class AnonymousInner { public abstract void mymethod(); } public class Outer_class { public static void main(String args[]) { AnonymousInner inner = new AnonymousInner() { public void mymethod() { System.out.println("This is an example of anonymous inner class"); } }; inner.mymethod(); } } Output: This is an example of anonymous inner class 4- Static Nested Classes عندما نعرف الInner class ك Static، يمكننا أن ننشئ object منه بدون الحاجه لإنشاء object من الouter class كذلك الStatic inner class لا يمكنه الوصول او استخدام الinstance variables or methods الموجودة بالouter class مثال لهذا النوع من الinner classes: class MyOuter { static class Nested { } } البرنامج التالي يوضح الفروقات بين انشاء object من static inner class و inner class: public class Outer { static class Nested { public void my_method() { System.out.println("This is my nested class"); } } public static void main(String args[]) { Outer.Nested nested = new Outer.Nested(); nested.my_method(); } } output: This is my nested class الى هنا نصل الى ختام موضوعنا. وفق الله الحميع لما يحبه ويرضاه.
  12. السلام عليكم ورحمة الله وبركاته في هذه المقاله سنناقش انواع الInner classes في الجافا في الجافا، كتابة class داخل class آخر مسموح، الكلاس الداخلي يسمى Nested class والخارجي يسمى Outer class. كمثال على الNested class: class Outer { class Nested { } } يمكن تقسيم الNested classes الى نوعين: Non-static nested classes Static nested classes نبدأ أولا بالInner classes Inner Classes (Non-static Nested Classes) يمكن التفكير ب الInner classes كحماية اضافية للكلاس الداخلي. من المعروف أن الكلاس لا يمكن ربطه باحد الaccess modifiers مثل (public, private, etc...)، ولكن يمكننا فعل ذلك اذا كان Inner class للInner classes ثلاثة أنواع: Inner classes Method-local inner classes Anonymous inner classes 1- Inner classes انشاء Inner class بسيط جدا، كل ما عليك فعله هو أن تعرف كلاس بداخل كلاس آخر كما رأينا بالأعلى سنعرف Private inner class بالمثال التالي: class Outer { int num; // inner class private class Inner { public void print() { System.out.println("This is an inner class"); } } // Accessing he inner class from the method within void display_Inner() { Inner inner = new Inner(); inner.print(); } } public class My_class { public static void main(String args[]) { // Instantiating the outer class Outer outer = new Outer(); // Accessing the display_Inner() method. outer.display_Inner(); } } Output: This is an inner class. في هذا المثال استعملنا method اضافية [()display_Inner] لعمل object من الprivate inner class ومن ثم استدعاء الميثود بداخله. باختصار، الطريقة الصحيحة لعمل Instantiating للInner class كالتالي: Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); 2- Method-local Inner Classes في الجافا، يمكننا أيضا ان نعرف كلاس داخل ميثود معينة، ولكن هذا الكلاس لا يمكن تعريفه أو استخدامه الا داخل نفس الميثود. المثال التالي يشرح كيفية استخدام الmethod-local inner class: public class Outer { // instance method of the outer class void my_Method() { int num = 23; // method-local inner class class MethodInner { public void print() { System.out.println("This is method inner class "+num); } } // end of inner class // Accessing the inner class within the same scope MethodInner inner = new MethodInner(); inner.print(); } public static void main(String args[]) { Outerclass outer = new Outerclass(); outer.my_Method(); } } Output: This is method inner class 23 3- Anonymous Inner Class هو كلاس يتم انشاؤه بدون اسم محدد له (Anonymous). عموما نستخدم هذا النوع من الكلاسات عندما نريد أن نعمل override لميثود في كلاس او انترفيس. مثال لكيفية انشاء Anonymous inner class: AnonymousInner an_inner = new AnonymousInner() { public void my_method() { ........ ........ } }; البرنامج التالي يوضح استخدام الAnonymous inner class لعمل override لميثود موجودة بabstract class: abstract class AnonymousInner { public abstract void mymethod(); } public class Outer_class { public static void main(String args[]) { AnonymousInner inner = new AnonymousInner() { public void mymethod() { System.out.println("This is an example of anonymous inner class"); } }; inner.mymethod(); } } Output: This is an example of anonymous inner class 4- Static Nested Classes عندما نعرف الInner class ك Static، يمكننا أن ننشئ object منه بدون الحاجه لإنشاء object من الouter class كذلك الStatic inner class لا يمكنه الوصول او استخدام الinstance variables or methods الموجودة بالouter class مثال لهذا النوع من الinner classes: class MyOuter { static class Nested { } } البرنامج التالي يوضح الفروقات بين انشاء object من static inner class و inner class: public class Outer { static class Nested { public void my_method() { System.out.println("This is my nested class"); } } public static void main(String args[]) { Outer.Nested nested = new Outer.Nested(); nested.my_method(); } } output: This is my nested class الى هنا نصل الى ختام موضوعنا. وفق الله الحميع لما يحبه ويرضاه. تم ترقية هذا الطرح المميز الى صفحة المقالات
  13. السلام عليكم، في هذه المقالة سنطلع على مقدمة لأهم ما قدمته الJava في اصدارها الثامن الجديد ألا وهي ال Lambda Expressions. هذه المقالة ستفترض: بأنك على معرفة تامة بالبرمجة عن طريق الجافا في اصداراتها السابقة معرفتك عن مبادئ البرمجة المتعلقة بالObject-Oriented Languages معرفتك لأهم أساسيات الجافا (Inheritance, Polymorphism, Abstraction and Encapsulation) لن تفترض معرفتك اي شيء متعلق بالنسخة الثامنة من جافا - لماذا ال Lambda ؟ من الصعب علي أن أشرح مدى أهمية وفوائد ال Lambda Expressions، لنفهم أهميتها تماما لابد من فهمها بالأصل، لذلك عليكم أن تثقوا بي في ما سأقوله (سيتضح المعنى أكثر كلما تقدمت بالشرح): لمن استخدم الجافا من قبل، يعلم أنها مبنية تماما على البرمجة الموضوعية (Object-Oriented Programming)، نستطيع الآن ان نضيف اليها نوع آخر وهو البرمجة الوظيفية (Functional Programming). ستعطي المبرمج امكانية كتابة اكواد مختصرة وقابلة للقراءة أكثر. ستضيف امكانية كتابة API's بسهولة اكبر وستسهل عملية استخدامها لاحقا. ستضيف الدعم للمعالجة المتعددة (Parallel Processing). سنركز على أول فائدة ونشرحها باستفاضة تاليًا. - ما الفرق بين ال(Object-Oreiented and Functional Programming) ؟ سأجيب على هذا السؤال باجابتي على سؤال أخر، هل فعلا الجافا تحتاج الى Functional Programming ؟ من سنين طويلة، والجافا كانت (ولا زالت وستظل) تعتمد بشكل أساسي على ال OO-Programming، ولا يوجد أي شيء لا تستطيع فعله بالجافا وتستطيع فعله بFunctional Language أخرى. إذا لماذا ؟ ال Functional Programming لا تضيف أي شيء جديد، سوا امكانية كتابة كود قابل للقراءة بسهولة أكبر وتمكنك من اكتشاف الأخطاء واصلاحها بسهولة. إذا، فكر بالFunctional Programming كأنها أداة اضافية للOO-Programming لتساعدنا وتسهل علينا كتابة الأكواد بالجافا. - ما هي المشاكل التي تستدعي استخدام الLambda Expressions ؟ سأوضح طريقة استعمال الLambda لحل بعض المشاكل التي تواجهنا عن طريق طرح المثال التالي: لنفترض بأنني أريد ان انشئ البرنامج الصغير المشهور لطباعة جملة (!Hello World) عن طريق استدعاء Method اخرى في الMain Method: public class Greeter { public void greet () { System.out.print("Hello World!"); { public static void main (String[] args) { Greeter greeter = new Greeter(); greeter.greet(); } } عندما يعمل هذا البرنامج الصغير، سيطبع لي جملة Hello World! بالكونسول. الآن، لنفترض بأني اريد ان اعدل الميثود greet() لأجعلها تأخذ انبوت معين، وبناء عليه تطبع شي مختلف لكل انبوت مختلف. المبرمج العادي سيفكر مباشرة بالSwitch statement وهو تقريبا الحل الأبسط للذهن ولكنه حل غير فعال. نريد أن نجد حل لهذه المشكلة، بحيث أننا نستطيع ان ندخل (سلوك) معين للميثود، بدلا من ان ندخل لها مجرد رقم أو جملة، نريد طريقة لإخبار الميثود مباشرة بما نريده عن طريق ادخال مجموعة من الأوامر (a block of code) مرة واحدة. قبل ان تأتي الجافا 8، كان بامكاننا حل هذه المشكلة عن طريق انشاء Interface و Class آخرين مساعدين كالتالي: public interface GreetingInterface { public void perform(); } public class GreetingClass implements GreetingInterface { @Override public void perform() { System.out.print("Hello World!"); } } ومن ثم نتجه لتعديل الClass الأول ليصبح كالتالي: public class Greeter { public void greet (GreetingInterface greeting) { greeting.perform(); { public static void main (String[] args) { Greeter greeter = new Greeter(); GreetingClass greetingClass = new GreetingClass(); greeter.greet(greetingClass); } } نلاحظ أن الميثود greet() الآن اصبحت تستقبل أوبجكت من Class implementeing GreetingInterface، بكلمات أخرى، أصبحت تستقبل (سلوك) لتنفذه بدلا من معطى لتتصرف بناء عليه. الآن نستطيع أن نعدل الميثود preform() في كلاس GreetingClass ليتعدل سلوك الميثود greet() بناء عليه. لكن هذه الطريقة طويلة وتتطلب انشاء Interface و Class آخرين فقط للقيام بمهمة بسيطة كهذه! هناك حل آخر لاختصار كل هذه الأكواد وتجاوز مشكلة انشاء كلاس جديد وهو عن طريق استخدام الAnonymous Inner Class. لن أتطرق لهذا الحل للحاجه لشرح العديد من المفاهيم بالرغم من بساطة الكود المستخدم (ولأن محور المقالة هو استخدام الLambda لحل المشكلة، وهو ما سنتحدث عنه تاليا). - كيف استخدم الLambda Expression ؟ كل ما سبق كان مقدمة للتالي: استخدام الLambda Expression لادخال مجموعة من الأوامر كInput الى الميثود greet(). قبل طرح الحل، تخيلوا معي لو استطعنا ان نحفظ مجموعة من الأوامر في variable معين، (لاحظوا انني قلت حفظ مجموعة من الأوامر وليس نتيجة تنفيذ هذه الأوامر). ماذا لو كان بامكاننا ان نكتب شيئا مثل: aBlockOfCode = public void printing () { System.out.print("Hello World!"); } بحيث يكون اسم الVariable عبارة عن printingFunction وبداخله 3 سطور من الأوامر. فعليا، هذا ما تتيحه لنا الLambda Expressions. مع تتطور الجافا، الآن أصبح الcompiler ذكي كفاية للتعرف على الميثود من دون تحديد (modifier, return type, or the name) في تعريف الميثود، كل ما عليك هو استخدام الرمز الخاص بالLambda Expressions وهو <- ليكون كالتالي: //nameOfTheVariable = (LIST OF INPUTS) -> {LIST OF COMMAND LINES}; printingFuncion = () -> System.out.print("Hello World!"); لكي تكتمل العبارة، لابد من اختيار النوع ال(Type) الصحيح، ولكن ماهو نوع هذا الVariable الجديد؟ الجافا اختارت ان يكون نوع هذا الفاريابل عبارة عن Interface بحيث يحتوي هذا ال Interface على ميثود لها Signature مطابق لLambda Expression: public class Test { public static void main(String[] args) { GreetingInterface printingFunction = () -> System.out.print("Hello World!"); } } public interface GreetingInterface { void perform(); } لاحظ ان الLambda Expression لا تحتوي على أي انبوت (وكذلك الميثود الموجودة بال Interface) لاحظ أيضا ان الLambda Expression لا تعيد أي قيمة (وكذلك الميثود الموجودة بال Interface من نوع void) لاحظ أيضا ان اسم الميثود بال Interface غير مهم أبدا، ما يهم هو اسم الInterface نفسه لأنك ستستعمله ك Type لLambda Expression. مثال آخر لLambda Expression لجمع رقمين: public class Test { public static void main(String[] args) { Add addingFunction = (int a, int b) -> a + b; } } public interface Add { int addingMethod(int a, int b); } بقي علينا استخدام هذا الExpression في الميثود، وتستطيع فعل ذلك عن طريق استدعاء الميثود الموجودة بالInterface. بالعودة الى مثال Hello World!: public class Greeter { public void greet (GreetingInterface greeting) { greeting.perform(); { public static void main (String[] args) { GreetingInterface printingFunction = () -> System.out.print("Hello World!"); greeter.greet(printingFunction.perform()); } } public interface GreetingInterface { void perform(); } ملاحظات: اذا كانت الLambda تحتوي على أكثر من سطر يجب استخدام ال{} بعد استخدام الرمز <- لا داعي لاستخدام الreturn Statement في حالة السطر الواحد (اذا اردت استخدام الreturn Statement يجب استخدام ال{}) الInterface المستعمل كType للLambda Expression يجب ان يكون Functional Interface (أي يحتوي على ميثود واحدة ففقط بsignature مطابق تماما للLambda Expression) الى هنا نصل لختام هذا الموضوع. وفق الله الجميع لما يحبه ويرضاه.
  14. السلام عليكم، في هذه المقالة سنطلع على مقدمة لأهم ما قدمته الJava في اصدارها الثامن الجديد ألا وهي ال Lambda Expressions. هذه المقالة ستفترض: بأنك على معرفة تامة بالبرمجة عن طريق الجافا في اصداراتها السابقة معرفتك عن مبادئ البرمجة المتعلقة بالObject-Oriented Languages معرفتك لأهم أساسيات الجافا (Inheritance, Polymorphism, Abstraction and Encapsulation) لن تفترض معرفتك اي شيء متعلق بالنسخة الثامنة من جافا - لماذا ال Lambda ؟ من الصعب علي أن أشرح مدى أهمية وفوائد ال Lambda Expressions، لنفهم أهميتها تماما لابد من فهمها بالأصل، لذلك عليكم أن تثقوا بي في ما سأقوله (سيتضح المعنى أكثر كلما تقدمت بالشرح): لمن استخدم الجافا من قبل، يعلم أنها مبنية تماما على البرمجة الموضوعية (Object-Oriented Programming)، نستطيع الآن ان نضيف اليها نوع آخر وهو البرمجة الوظيفية (Functional Programming). ستعطي المبرمج امكانية كتابة اكواد مختصرة وقابلة للقراءة أكثر. ستضيف امكانية كتابة API's بسهولة اكبر وستسهل عملية استخدامها لاحقا. ستضيف الدعم للمعالجة المتعددة (Parallel Processing). سنركز على أول فائدة ونشرحها باستفاضة تاليًا. - ما الفرق بين ال(Object-Oreiented and Functional Programming) ؟ سأجيب على هذا السؤال باجابتي على سؤال أخر، هل فعلا الجافا تحتاج الى Functional Programming ؟ من سنين طويلة، والجافا كانت (ولا زالت وستظل) تعتمد بشكل أساسي على ال OO-Programming، ولا يوجد أي شيء لا تستطيع فعله بالجافا وتستطيع فعله بFunctional Language أخرى. إذا لماذا ؟ ال Functional Programming لا تضيف أي شيء جديد، سوا امكانية كتابة كود قابل للقراءة بسهولة أكبر وتمكنك من اكتشاف الأخطاء واصلاحها بسهولة. إذا، فكر بالFunctional Programming كأنها أداة اضافية للOO-Programming لتساعدنا وتسهل علينا كتابة الأكواد بالجافا. - ما هي المشاكل التي تستدعي استخدام الLambda Expressions ؟ سأوضح طريقة استعمال الLambda لحل بعض المشاكل التي تواجهنا عن طريق طرح المثال التالي: لنفترض بأنني أريد ان انشئ البرنامج الصغير المشهور لطباعة جملة (!Hello World) عن طريق استدعاء Method اخرى في الMain Method: public class Greeter { public void greet () { System.out.print("Hello World!"); { public static void main (String[] args) { Greeter greeter = new Greeter(); greeter.greet(); } } عندما يعمل هذا البرنامج الصغير، سيطبع لي جملة Hello World! بالكونسول. الآن، لنفترض بأني اريد ان اعدل الميثود greet() لأجعلها تأخذ انبوت معين، وبناء عليه تطبع شي مختلف لكل انبوت مختلف. المبرمج العادي سيفكر مباشرة بالSwitch statement وهو تقريبا الحل الأبسط للذهن ولكنه حل غير فعال. نريد أن نجد حل لهذه المشكلة، بحيث أننا نستطيع ان ندخل (سلوك) معين للميثود، بدلا من ان ندخل لها مجرد رقم أو جملة، نريد طريقة لإخبار الميثود مباشرة بما نريده عن طريق ادخال مجموعة من الأوامر (a block of code) مرة واحدة. قبل ان تأتي الجافا 8، كان بامكاننا حل هذه المشكلة عن طريق انشاء Interface و Class آخرين مساعدين كالتالي: public interface GreetingInterface { public void perform(); } public class GreetingClass implements GreetingInterface { @Override public void perform() { System.out.print("Hello World!"); } } ومن ثم نتجه لتعديل الClass الأول ليصبح كالتالي: public class Greeter { public void greet (GreetingInterface greeting) { greeting.perform(); { public static void main (String[] args) { Greeter greeter = new Greeter(); GreetingClass greetingClass = new GreetingClass(); greeter.greet(greetingClass); } } نلاحظ أن الميثود greet() الآن اصبحت تستقبل أوبجكت من Class implementeing GreetingInterface، بكلمات أخرى، أصبحت تستقبل (سلوك) لتنفذه بدلا من معطى لتتصرف بناء عليه. الآن نستطيع أن نعدل الميثود preform() في كلاس GreetingClass ليتعدل سلوك الميثود greet() بناء عليه. لكن هذه الطريقة طويلة وتتطلب انشاء Interface و Class آخرين فقط للقيام بمهمة بسيطة كهذه! هناك حل آخر لاختصار كل هذه الأكواد وتجاوز مشكلة انشاء كلاس جديد وهو عن طريق استخدام الAnonymous Inner Class. لن أتطرق لهذا الحل للحاجه لشرح العديد من المفاهيم بالرغم من بساطة الكود المستخدم (ولأن محور المقالة هو استخدام الLambda لحل المشكلة، وهو ما سنتحدث عنه تاليا). - كيف استخدم الLambda Expression ؟ كل ما سبق كان مقدمة للتالي: استخدام الLambda Expression لادخال مجموعة من الأوامر كInput الى الميثود greet(). قبل طرح الحل، تخيلوا معي لو استطعنا ان نحفظ مجموعة من الأوامر في variable معين، (لاحظوا انني قلت حفظ مجموعة من الأوامر وليس نتيجة تنفيذ هذه الأوامر). ماذا لو كان بامكاننا ان نكتب شيئا مثل: aBlockOfCode = public void printing () { System.out.print("Hello World!"); } بحيث يكون اسم الVariable عبارة عن printingFunction وبداخله 3 سطور من الأوامر. فعليا، هذا ما تتيحه لنا الLambda Expressions. مع تتطور الجافا، الآن أصبح الcompiler ذكي كفاية للتعرف على الميثود من دون تحديد (modifier, return type, or the name) في تعريف الميثود، كل ما عليك هو استخدام الرمز الخاص بالLambda Expressions وهو <- ليكون كالتالي: //nameOfTheVariable = (LIST OF INPUTS) -> {LIST OF COMMAND LINES}; printingFuncion = () -> System.out.print("Hello World!"); لكي تكتمل العبارة، لابد من اختيار النوع ال(Type) الصحيح، ولكن ماهو نوع هذا الVariable الجديد؟ الجافا اختارت ان يكون نوع هذا الفاريابل عبارة عن Interface بحيث يحتوي هذا ال Interface على ميثود لها Signature مطابق لLambda Expression: public class Test { public static void main(String[] args) { GreetingInterface printingFunction = () -> System.out.print("Hello World!"); } } public interface GreetingInterface { void perform(); } لاحظ ان الLambda Expression لا تحتوي على أي انبوت (وكذلك الميثود الموجودة بال Interface) لاحظ أيضا ان الLambda Expression لا تعيد أي قيمة (وكذلك الميثود الموجودة بال Interface من نوع void) لاحظ أيضا ان اسم الميثود بال Interface غير مهم أبدا، ما يهم هو اسم الInterface نفسه لأنك ستستعمله ك Type لLambda Expression. مثال آخر لLambda Expression لجمع رقمين: public class Test { public static void main(String[] args) { Add addingFunction = (int a, int b) -> a + b; } } public interface Add { int addingMethod(int a, int b); } بقي علينا استخدام هذا الExpression في الميثود، وتستطيع فعل ذلك عن طريق استدعاء الميثود الموجودة بالInterface. بالعودة الى مثال Hello World!: public class Greeter { public void greet (GreetingInterface greeting) { greeting.perform(); { public static void main (String[] args) { GreetingInterface printingFunction = () -> System.out.print("Hello World!"); greeter.greet(printingFunction.perform()); } } public interface GreetingInterface { void perform(); } ملاحظات: اذا كانت الLambda تحتوي على أكثر من سطر يجب استخدام ال{} بعد استخدام الرمز <- لا داعي لاستخدام الreturn Statement في حالة السطر الواحد (اذا اردت استخدام الreturn Statement يجب استخدام ال{}) الInterface المستعمل كType للLambda Expression يجب ان يكون Functional Interface (أي يحتوي على ميثود واحدة ففقط بsignature مطابق تماما للLambda Expression) الى هنا نصل لختام هذا الموضوع. وفق الله الجميع لما يحبه ويرضاه. تم ترقية هذا الطرح المميز الى صفحة المقالات

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل