مقدمة
كما نعلم، جافا هي لغة برمجة كائنية التوجه. وهذا هو المفهوم الأساسي، لأن القول بأن أساس الأساسيات هو أن كل شيء هو كائن. يتم وصف الكائنات باستخدام الفئات.
الطبقات بدورها لها حالة وسلوك. على سبيل المثال، قد يكون للحساب البنكي حالة على شكل مبلغ من المال في الحساب وله سلوك زيادة الرصيد وتقليله. يتم تنفيذ السلوك في Java باستخدام الأساليب. يتم تقديم كيفية وصف الأساليب في بداية رحلة تعلم Java. على سبيل المثال، في البرنامج التعليمي الرسمي من Oracle: "
Defining Methods ". هناك جانبان مهمان هنا:
- كل طريقة لها توقيع. يتكون التوقيع من اسم الطريقة ومعلمات الإدخال الخاصة بها؛
- يجب أن تحدد الأساليب نوع الإرجاع؛
- نوع الإرجاع ليس جزءًا من توقيع الطريقة.
مرة أخرى، هذا نتيجة لحقيقة أن Java هي لغة مكتوبة بقوة ويريد المترجم أن يفهم مسبقًا الأنواع المستخدمة قدر الإمكان. مرة أخرى، لحمايتنا من الأخطاء. بشكل عام، كل شيء للخير. حسنًا، يبدو لي أن هذا يغرس فينا مرة أخرى ثقافة التعامل مع البيانات. لذلك، بالنسبة للطرق يتم تحديد نوع القيمة. ولإرجاع نفس القيمة من الطرق، يتم استخدام الكلمة الأساسية
return
.
بيان إرجاع الكلمات الرئيسية في جافا
تشير الكلمة الأساسية للبيان
return
إلى "بيانات التحكم في التدفق" كما تمت مناقشتها في برنامج Oracle التعليمي "
بيانات التحكم في التدفق ". يمكنك أيضًا أن تقرأ عن كيفية إرجاع القيم في البرنامج التعليمي الرسمي: "
إرجاع قيمة من طريقة ". يراقب المترجم بعناية، قدر استطاعته، أن القيمة التي يتم إرجاعها من إحدى الطرق تتطابق مع نوع قيمة الإرجاع المحدد بواسطة الطريقة.
دعونا نستخدم IDE عبر الإنترنت من موقع Tutorialspoint كمثال . دعونا نلقي نظرة على المثال الأصلي:
public class HelloWorld {
public static void main(String []args) {
System.out.println("Hello World");
}
}
كما نرى، يتم تنفيذ طريقة هنا
main
، وهي نقطة الدخول إلى البرنامج. يتم تنفيذ أسطر التعليمات البرمجية من الأعلى إلى الأسفل. لا يمكن لطريقتنا
main
إرجاع القيم، وإلا فسنتلقى خطأ: "
Error: Main method must return a value of type void
". لذلك، سيتم إخراج الطريقة ببساطة إلى الشاشة. لننقل الآن استلام السلسلة إلى طريقة منفصلة لتلقي الرسالة:
public class HelloWorld {
public static void main(String []args) {
System.out.println(getHelloMessage());
}
public static String getHelloMessage() {
return "Hello World";
}
}
كما نرى، باستخدام الكلمة الأساسية
return
قمنا بتحديد القيمة المرجعة، والتي استخدمناها لاحقًا في الطريقة
println
. وقد أشرنا في وصف (تعريف) الطريقة
getHelloMessage
إلى أنها ستعيدنا
String
. يسمح هذا للمترجم بالتحقق من أن إجراءات الطريقة متوافقة مع الطريقة التي تم الإعلان عنها. وبطبيعة الحال، يمكن أن يكون نوع القيمة المرجعة المحددة في تعريف الطريقة أوسع من نوع القيمة التي يتم إرجاعها من الكود، أي. الشيء الرئيسي هو أن الأنواع يتم اختزالها مع بعضها البعض. وإلا فسوف نحصل على خطأ في وقت الترجمة: "
error: incompatible types
". بالمناسبة، ربما نشأ السؤال على الفور: لماذا
return
ينطبق ذلك على مشغلي التحكم في تدفق البرنامج؟ ولكن لأنه يمكن أن يعطل التدفق الطبيعي للبرنامج من الأعلى إلى الأسفل. على سبيل المثال:
public class HelloWorld {
public static void main(String []args){
if (args.length == 0) {
return;
}
for (String arg : args) {
System.out.println(arg);
}
}
}
كما يتبين من المثال، فإننا نقوم بمقاطعة تنفيذ الطريقة
main
إذا تم استدعاء برنامج Java الخاص بنا بدون معلمات. من المهم أن تتذكر أنه إذا كان لديك
return
الرمز، فسيصبح غير قابل للوصول. وسوف يلاحظ مترجمنا الذكي ذلك ولن يسمح لك بتشغيل مثل هذا البرنامج. على سبيل المثال، لن يتم تجميع هذا الرمز:
public static void main(String []args) {
System.out.println("1");
return;
System.out.println("2");
}
هناك اختراق قذر للالتفاف على هذا. على سبيل المثال، لأغراض التصحيح أو لسبب آخر. يمكن إصلاح الكود أعلاه عن طريق تغليفه
return
في
if
كتلة:
if (2==2) {
return;
}
بيان الإرجاع في معالجة الأخطاء
هناك ظرف واحد صعب للغاية - يمكننا استخدامه
return
مع معالجة الأخطاء. أود أن أقول على الفور أن استخدامه
return
في
catch
كتلة هو شكل سيء للغاية، لذا يجب عليك تجنبه. لكننا بحاجة إلى مثال، أليس كذلك؟ هنا هو:
public class HelloWorld {
public static void main(String []args) {
System.out.println("Value is: " + getIntValue());
}
public static int getIntValue() {
int value = 1;
try {
System.out.println("Something terrible happens");
throw new Exception();
} catch (Exception e) {
System.out.println("Catched value: " + value);
return value;
} finally {
value++;
System.out.println("New value: " + value);
}
}
}
للوهلة الأولى، يبدو أنه يجب إرجاع 2، لأنه
finally
يتم تنفيذه دائمًا.
finally
لكن لا، ستكون القيمة 1، وسيتم تجاهل التغيير الذي تم إجراؤه على المتغير . علاوة على ذلك، إذا كان
value
يحتوي على كائن وقلنا
finally
،
value = null
فسيظل
catch
يُرجع مرجعًا إلى الكائن، وليس
null
. ولكن من الكتلة كان
finally
المشغل
return
سيعمل بشكل صحيح. من الواضح أن زملائك لن يشكروك على هذه الهدية.
void.class
وأخيرا. يمكنك كتابة بناء غريب مثل
void.class
. يبدو، لماذا وما هي النقطة؟ في الواقع، في مختلف الأطر والحالات الصعبة حيث يتم استخدام
Java Reflection API ، قد يكون هذا ضروريًا للغاية. على سبيل المثال، يمكنك التحقق من النوع الذي تُرجعه الطريقة:
import java.lang.reflect.Method;
public class HelloWorld {
public void getVoidValue() {
}
public static void main(String[] args) {
for (Method method : HelloWorld.class.getDeclaredMethods()) {
System.out.println(method.getReturnType() == void.class);
}
}
}
يمكن أن يكون هذا مفيدًا في أطر الاختبار حيث يكون من الضروري استبدال الكود الحقيقي للطرق. لكن للقيام بذلك، عليك أن تفهم كيف تتصرف هذه الطريقة (أي الأنواع التي تُرجعها). هناك طريقة ثانية لتنفيذ الطريقة
main
من الكود أعلاه:
public static void main (String[] args) {
for (Method method : HelloWorld.class.getDeclaredMethods()) {
System.out.println(method.getReturnType() == Void.TYPE);
}
}
يمكن قراءة مناقشة مثيرة للاهتمام حول الفرق بينهما في Stackoverflow:
ما الفرق بين java.lang.Void وvoid؟ # فياتشيسلاف
GO TO FULL VERSION