Kotlin / التزامن والتكامل والتصميم المترابط / الدرس 16
حماية الحد الفاصل بين Kotlin وJava
عالج قابلية الخلو غير المؤكدة في أنواع المنصة، وعقود المجموعات، والتمثيل العددي، وشكل الواجهة أمام Java صراحة.
في هذه الصفحة
أهداف الدرس
- اشرح كيف تضعف أنواع منصة Java افتراضا محليا بأن القيمة غير خالية.
- راجع الواجهة التي يراها مستدعي Java فعليا، ولا تفترض ظهور صياغة Kotlin كما هي.
يحفظ التكامل الاتصال ولا يحفظ كل ضمان نوعي
تستطيع Kotlin/JVM استدعاء مكتبات Java وإتاحة تصريحات Kotlin لمستدعي Java. وقد تكون معلومات الخلو ناقصة عند هذا الحد. يمكن أن يظهر مرجع Java لا يحمل وسوم خلو يتعرف عليها المترجم كنوع منصة، فيتيح لشيفرة Kotlin معاملته كخال أو غير خال، مع بقاء احتمال فشل أثناء التشغيل. أنشئ تمثيلا محليا متحققا قرب الحد بدلا من نشر افتراضات المنصة في منطق العمل. يساعد الوسم الأدوات على نقل القصد، لكنه لا يمنع تنفيذ Java خاطئا فعليا من إرجاع null أو تعديل مجموعة على غير المتوقع.
طبّع الخلو غير المؤكد قبل استخدام المجال
يتضمن المثال ذو الملفين صنف Java قديما افتراضيا يعيد null عمدا. تستقبل Kotlin النتيجة في متغير محلي مصرح بخلوه، ثم تختار بديلا للعرض. يجب ترجمة المصدرين معا ببناء مختلط اللغات متوافق؛ ولا تمثل أي كتلة وحدها تطبيقا كاملا قابلا للتشغيل. لا تستخدم !! لمجرد قول وثائق Java إن القيمة ينبغي أن توجد. إذا خالف الغياب عقد العمل، فأعد إخفاق تكامل صريحا بدلا من اعتبار نص بديل، بصمت، هوية صالحة في المجال.
public final class LegacyNames {
public static String fetchName() { return null; }
}
يعيد هذا الصنف null عمدا، ولا يحتوي main. إنه جزء واحد من مثال Java وKotlin مختلط مقترح، ولم يُترجم.
fun main() {
val name: String? = LegacyNames.fetchName()
println(name ?: "missing name")
}
missing name
عند بناء هذا المصدر مع صنف Java السابق، يكون المخرج المتوقع missing name. هذه نتيجة مستنتجة بالتحليل؛ ولم يُنفّذ بناء مختلط اللغتين.
راجع التعديل والاستثناءات عبر حد اللغتين
لا تنشئ واجهات مجموعات Java وواجهات القراءة فقط في Kotlin ضمانا للثبات العميق عند تبادل القيم. قد تحتفظ Java بمرجع آخر، أو تُدخل null غير متوقع حيث لا تحمي الوسوم والأنواع العامة العقد، أو تعيد كائنا غير قابل للتعديل يرمي عند محاولة تغييره. تحقق من المدخلات وانسخ عندما يشترط عقد الملكية لقطة. تعامل Kotlin الاستثناءات باعتبارها غير مفحوصة إلزاميا، بينما قد يحتاج مستدعي Java تصريح throws مناسبا عبر وسوم تكامل لواجهة محددة. صمّم عقد الإخفاق أمام المستدعي، ولا تفترض فرض اللغتين القواعد نفسها.
استخدم أنواع قيم Java الدقيقة حيث تناسب الدلالة
تستطيع Kotlin/JVM استخدام java.math.BigDecimal للحساب العشري. يحفظ البناء من نص عشري القيمة المكتوبة، بينما قد يحفظ البناء من Double التقريب الثنائي لذلك العدد. يجمع المثال قيمتين منشأتين من نصوص دقيقة ويطبع صيغة عشرية عادية. يظل نموذج المال الحقيقي بحاجة إلى تحديد العملة والمقياس وطريقة التقريب وحدود المجال أو التجاوز ومتطلبات التدقيق. BigDecimal أداة، وليس مجالا ماليا كاملا. وقد تختلف المساواة والمقارنة العددية في التعامل مع المقياس؛ فاختر المقارنة التي تناسب المعنى التجاري.
import java.math.BigDecimal
fun main() {
val first = BigDecimal("0.10")
val second = BigDecimal("0.20")
val total = first.add(second)
println(total.toPlainString())
println(total.compareTo(BigDecimal("0.3")) == 0)
}
0.30
true
المخرج المتوقع 0.30 ثم true. تفحص compareTo هنا الترتيب العددي رغم اختلاف المقاييس المكتوبة. يحتاج البرنامج واجهات JVM، ولم يُترجم أو يُنفّذ.
افحص ما يظهر لمستدعي Java فعليا
تظهر خصائص Kotlin عادة في صورة getters وsetters أمام Java، وتُترجم الدوال العليا إلى صنف واجهة ملف مولد، ما لم يُضبط خلاف ذلك. لا تنشئ المعاملات الافتراضية كل تحميل زائد متوقع في Java تلقائيا، ولا تصبح دوال companion طرق static عادية تلقائيا. تعالج وسوم مثل JvmName وJvmStatic وJvmOverloads وThrows احتياجات تكامل بعينها وفقا لقواعد محددة. استخدمها لخدمة عقد مستدع معلن، لا كزينة عامة. راجع تواقيع الواجهة المولدة واختبارات اللغتين عند توفر الأدوات؛ ولم تُجر الدورة فحص bytecode أو تنفيذ تكامل.
الأخطاء الشائعة وإصلاحها
تفشل قيمة معادة من Java عند استخدامها بوصفها غير خالية في Kotlin.
- لماذا يحدث؟
- قُبل نوع منصة كتوقع بعدم الخلو دون تحقق عند الحد.
- كيف تصلحه؟
- طبّع قابلية الخلو بالقرب من حد التكامل.
- كيف تتجنب تكراره؟
- اختبر صراحة حالات البيانات الغائبة والمشوهة المعادة من Java.
يكشف المخرج العشري تقريبا ثنائيا غير متوقع.
- لماذا يحدث؟
- أُنشئت القيمة العشرية عبر مدخل Double غير دقيق.
- كيف تصلحه؟
- استخدم مدخلا عشريا دقيقا ملائما، وحدّد سياسة التقريب صراحة.
- كيف تتجنب تكراره؟
- أبق تمثيل المال مستقلا عن تنسيق عرضه.
لا يستطيع مستدعي Java استخدام التحميل الزائد المتوقع للمعاملات الافتراضية.
- لماذا يحدث؟
- افتُرض أن وسائل الراحة في مصدر Kotlin تحدد شكل واجهة Java أيضا.
- كيف تصلحه؟
- راجع التواقيع المولدة، وأضف دعما مقصودا للتحميل الزائد عند الحاجة.
- كيف تتجنب تكراره؟
- ضمّن مستدعي Java ممثلين في مراجعة الواجهة.
اختبر فهمك
1. هل ينبغي تحويل null غير متوقع لمعرف Java مطلوب إلى نص فارغ؟
اعرض الحل المشروح
فقط إذا كانت تلك سياسة المجال الصريحة، وهو أمر غير شائع لهوية مطلوبة. قد يخفي النص الفارغ إخفاق التكامل، ويستهدف لاحقا مسارا خاطئا. فضّل إخفاقا متحققا أو نتيجة منظمة عند المحول، مع حفظ سياق تشخيصي آمن دون كشف بيانات حساسة.
2. هل يضمن استخدام BigDecimal وحده صحة السلوك المالي؟
اعرض الحل المشروح
لا. فهو يوفر حسابا عشريا بعمليات محددة، لكن على التطبيق تحديد العملة والمقياس المسموح والتقريب والتحقق ودلالات المعاملة. لا يثبت المثال أيا من هذه السياسات التجارية، ومخرجه متوقع بالتحليل لا مرصود بالتنفيذ، لأن مترجم Kotlin لم يتوفر.
أهم ما تعلمته
- يجب أن تحول محولات التكامل بيانات المنصة غير المؤكدة إلى أنواع محلية متحققة.
- تحتاج التواقيع الظاهرة أمام Java والدلالات العددية إلى مراجعة صريحة.