Java से Kotlin कोड कॉल करना

इस कोडलैब में, आप अपने Kotlin कोड को लिखने या कस्टमाइज़ करने का तरीका जानेंगे, ताकि वह Java कोड के ज़रिए आसानी से कॉल किया जा सके.

आप क्या #39;जानेंगे

  • @JvmField, @JvmStatic, और अन्य एनोटेशन का इस्तेमाल कैसे करें.
  • Java कोड से, Kotlin लैंग्वेज की कुछ सुविधाओं को ऐक्सेस करने की सीमाएं.

आपको पहले से क्या पता होना चाहिए

यह कोडलैब प्रोग्रामर के लिए लिखा गया है. यह Java और Kotlin की बुनियादी जानकारी रखता है.

यह कोडलैब एक बड़े प्रोजेक्ट के उस हिस्से को सिम्युलेट करता है जिसे Java प्रोग्रामिंग भाषा में लिखा गया है. इसमें नए Kotlin कोड को शामिल किया जाता है.

चीज़ों को आसान बनाने के लिए, हमारे पास एक और .java फ़ाइल होगी, जिसका नाम UseCase.java है. इससे मौजूदा कोड बेस के बारे में पता चलेगा.

हम मानते हैं कि हमने हाल ही में Java में लिखे गए कुछ फ़ंक्शन को, Kotlin में लिखे नए वर्शन से बदल दिया है. हमें इसे इंटिग्रेट करना होगा.

प्रोजेक्ट इंपोर्ट करें

प्रोजेक्ट और #39; के कोड को यहां GitHub प्रोजेक्ट से क्लोन किया जा सकता है: GitHub

इसके अलावा, आप यहां दिए गए ZIP संग्रह से भी प्रोजेक्ट को डाउनलोड और एक्सट्रैक्ट कर सकते हैं:

पिन डाउनलोड करें

अगर आप IntelliJ IDEA का इस्तेमाल कर रहे हैं, तो "प्रोजेक्ट इंपोर्ट करें" चुनें.

अगर आप Android Studio का इस्तेमाल कर रहे हैं, तो "प्रोजेक्ट इंपोर्ट करें (Gradle, Eclipse ADT, वगैरह.)'चुनें.

UseCase.java को खोलें और जो गड़बड़ियां हमें मिली हैं उनकी मदद से काम करना शुरू करें.

किसी समस्या के साथ पहला फ़ंक्शन registerGuest है:

public static User registerGuest(String name) {
   User guest = new User(Repository.getNextGuestId(), StringUtils.nameToLogin(name), name);
   Repository.addUser(guest);
   return guest;
}

Repository.getNextGuestId() और Repository.addUser(...), दोनों की गड़बड़ियां एक जैसी हैं: "नॉन-स्टैटिक को स्टैटिक कॉन्टेक्स्ट से ऐक्सेस नहीं किया जा सकता.&कोटेशन;

आइए, अब Kotlin फ़ाइलों में से किसी एक को देखते हैं. Repository.kt फ़ाइल खोलें.

हम देख रहे हैं कि हमारा रिपॉज़िटरी एक सिंगलटन है जिसे ऑब्जेक्ट कीवर्ड का इस्तेमाल करके तय किया जाता है. समस्या यह है कि Kotlin हमारे क्लास के अंदर एक स्टैटिक इंस्टेंस को जनरेट करने के बजाय, एक स्टैटिक प्रॉपर्टी और मेथड को दिखाता है.

उदाहरण के लिए, Repository.getNextGuestId() का इस्तेमाल Repository.INSTANCE.getNextGuestId() का इस्तेमाल करके किया जा सकता है, लेकिन यह एक बेहतर तरीका है.

हम Kotlin को स्टैटिक मेथड और प्रॉपर्टी जनरेट करने के लिए, @JvmStatic के साथ रिपॉज़िटरी की सार्वजनिक प्रॉपर्टी और मेथड की व्याख्या कर सकते हैं:

object Repository {
   val BACKUP_PATH = "/backup/user.repo"

   private val _users = mutableListOf<User>()
   private var _nextGuestId = 1000

   @JvmStatic
   val users: List<User>
       get() = _users

   @JvmStatic
   val nextGuestId
       get() = _nextGuestId++

   init {
       _users.add(User(100, "josh", "Joshua Calvert", listOf("admin", "staff", "sys")))
       _users.add(User(101, "dahybi", "Dahybi Yadev", listOf("staff", "nodes")))
       _users.add(User(102, "sarha", "Sarha Mitcham", listOf("admin", "staff", "sys")))
       _users.add(User(103, "warlow", groups = listOf("staff", "inactive")))
   }

   @JvmStatic
   fun saveAs(path: String?):Boolean {
       val backupPath = path ?: return false

       val outputFile = File(backupPath)
       if (!outputFile.canWrite()) {
           throw FileNotFoundException("Could not write to file: $backupPath")
       }
       // Write data...
       return true
   }

   @JvmStatic
   fun addUser(user: User) {
       // Ensure the user isn't already in the collection.
       val existingUser = users.find { user.id == it.id }
       existingUser?.let { _users.remove(it) }
       // Add the user.
       _users.add(user)
   }
}

अपने आईडीई का इस्तेमाल करके, अपने कोड में @JvmStatic एनोटेशन जोड़ें.

अगर हम UseCase.java पर वापस स्विच करते हैं, तो Repository.BACKUP_PATH को छोड़कर Repository की प्रॉपर्टी और मेथड की गड़बड़ियां अब नहीं होंगी. हम बाद में आएंगे.

अभी के लिए, registerGuest() तरीके में अगली गड़बड़ी ठीक करें.

आइए इस स्थिति पर विचार करें: हमारे पास स्ट्रिंग कार्रवाइयों के लिए कई स्थिर फ़ंक्शन वाली StringUtils क्लास थी. जब हमने इसे Kotlin में बदला था, तो हमने उन तरीकों को एक्सटेंशन फ़ंक्शन में बदल दिया था. Java में एक्सटेंशन फ़ंक्शन नहीं होते, इसलिए Kotlin इन तरीकों को स्टैटिक फ़ंक्शन के तौर पर कंपाइल करती है.

हमें खेद है कि अगर हम UseCase.java में registerGuest() के तरीके पर गौर करें, तो हम देख सकते हैं कि कुछ और #39; बिल्कुल सही नहीं है:

User guest = new User(Repository.getNextGuestId(), StringUtils.nameToLogin(name), name);

इसकी वजह यह है कि Kotlin में इन "top-level&कोटेशन; या पैकेज लेवल के फ़ंक्शन को किसी ऐसी क्लास में रखा जाता है जिसका नाम फ़ाइल नाम पर आधारित होता है. इस मामले में, फ़ाइल का नाम StringUtils.kt है, इसलिए उससे जुड़ी क्लास का नाम StringUtilsKt है.

हम अपने StringUtils के सभी रेफ़रंस को StringUtilsKt में बदल सकते हैं और इस गड़बड़ी को ठीक कर सकते हैं. हालांकि, यह #33 सही नहीं है, क्योंकि:

  • हमारे कोड में ऐसी कई जगहें हो सकती हैं जिन्हें अपडेट करना होगा.
  • नाम अजीब है.

इसलिए, अपने Java कोड को रीफ़ैक्टर करने के बजाय, अपने Kotlin कोड को इन तरीकों से किसी अलग नाम से अपडेट करने दें.

StringUtils.Kt खोलें और पैकेज का यह एलान ढूंढें:

package com.google.example.javafriendlykotlin

हम @file:JvmName एनोटेशन का इस्तेमाल करके, Kotlin को पैकेज लेवल के तरीकों के लिए किसी अलग नाम का इस्तेमाल करने के लिए कह सकते हैं. यूआरएल की क्लास StringUtils को नाम देने के लिए, इस एनोटेशन का इस्तेमाल करें.

@file:JvmName("StringUtils")

package com.google.example.javafriendlykotlin

अब, अगर हम UseCase.java को फिर से देखते हैं, तो हम देख सकते हैं कि StringUtils.nameToLogin() की गड़बड़ी ठीक हो गई है.

माफ़ करें, User के लिए कंस्ट्रक्टर में पास किए जा रहे पैरामीटर के बारे में इस गड़बड़ी को नए पैरामीटर से बदल दिया गया. अगले चरण पर जाएं और UseCase.registerGuest() में इस आखिरी गड़बड़ी को ठीक करें.

Kotlin, पैरामीटर के लिए डिफ़ॉल्ट वैल्यू के साथ काम करता है. हम Repository.kt के init ब्लॉक में जाकर देख सकते हैं कि उनका इस्तेमाल कैसे किया जाता है.

Repository.kt:

_users.add(User(102, "sarha", "Sarha Mitcham", listOf("admin", "staff", "sys")))
_users.add(User(103, "warlow", groups = listOf("staff", "inactive")))

हम देख सकते हैं कि उपयोगकर्ता के लिए & लेने वाले &कोटेशन; हम displayName के लिए कोई वैल्यू नहीं रख सकते. ऐसा इसलिए, क्योंकि इसके लिए #33; डिफ़ॉल्ट वैल्यू User.kt में तय होती है.

User.kt:

data class User(
   val id: Int,
   val username: String,
   val displayName: String = username.toTitleCase(),
   val groups: List<String> = listOf("guest")
)

हालांकि, Java से मेथड को कॉल करते समय, यह काम नहीं करता.

UseCase.java:

User guest = new User(Repository.getNextGuestId(), StringUtils.nameToLogin(name), name);

डिफ़ॉल्ट प्रोग्रामिंग कोड, Java प्रोग्रामिंग लैंग्वेज में काम नहीं करता. इस गड़बड़ी को ठीक करने के लिए, Kotlin को @JvmOverloads एनोटेशन की मदद से, हमारे कंस्ट्रक्टर के लिए ओवरलोड करने के लिए कहें.

सबसे पहले, हमें User.kt में थोड़ा बदलाव करना होगा.

User क्लास में सिर्फ़ एक, मुख्य कंस्ट्रक्टर होता है और कंस्ट्रक्टर में कोई भी एनोटेशन शामिल नहीं होता है. इसलिए, constructor कीवर्ड को हटा दिया गया है. अब जब भी हम इसे एनोटेट करना चाहते हैं, तो constructor कीवर्ड को इसमें शामिल करना ज़रूरी है:

data class User constructor(
    val id: Int,
    val username: String,
    val displayName: String = username.toTitleCase(),
    val groups: List<String> = listOf("guest")
)

constructor कीवर्ड मौजूद होने पर, हम @JvmOverloads एनोटेशन जोड़ सकते हैं:

data class User @JvmOverloads constructor(
    val id: Int,
    val username: String,
    val displayName: String = username.toTitleCase(),
    val groups: List<String> = listOf("guest")
)

अगर हम UseCase.java पर स्विच करते हैं, तो हम देख सकते हैं कि registerGuest फ़ंक्शन में कोई और गड़बड़ी नहीं है!

हमारा अगला कदम, UseCase.getSystemUsers() मेंuser.hasSystemAccess() पर टूटे हुए कॉल को ठीक करना है. इसके लिए, अगले चरण पर जाएं या इस बारे में ज़्यादा जानने के लिए, आगे पढ़ें कि गड़बड़ी को ठीक करने के लिए, @JvmOverloads ने क्या किया है.

@JvmOverloads

यह समझने के लिए कि @JvmOverloads क्या करता है, UseCase.java में एक जांच विधि बनाएं:

private void testJvmOverloads() {
   User syrinx = new User(1001, "syrinx");
   User ione = new User(1002, "ione", "Ione Saldana");

   List<String> groups = new ArrayList<>();
   groups.add("staff");
   User beaulieu = new User(1002, "beaulieu", groups);
}

हम सिर्फ़ दो पैरामीटर, id और username के साथ User बना सकते हैं:

User syrinx = new User(1001, "syrinx");

हम groups के लिए डिफ़ॉल्ट वैल्यू का इस्तेमाल करते हुए, displayName के लिए तीसरा पैरामीटर शामिल करके भी User बना सकते हैं:

User ione = new User(1002, "ione", "Ione Saldana");

लेकिन displayName को छोड़ना संभव नहीं है और अतिरिक्त कोड लिखे बिना groups के लिए सिर्फ़ एक वैल्यू देनी होगी:

इसलिए, आइए उस लाइन को मिटाएं या टिप्पणी करने के लिए उसे "//' के साथ दिखाएं.

Kotlin में, अगर हम डिफ़ॉल्ट और नॉन-डिफ़ॉल्ट पैरामीटर को जोड़ना चाहते हैं, तो हमें नाम वाले पैरामीटर का इस्तेमाल करना होगा.

// This doesn't work...
User(104, "warlow", listOf("staff", "inactive"))
// But using named parameters, it does...
User(104, "warlow", groups = listOf("staff", "inactive"))

वजह यह है कि Kotlin, कंस्ट्रक्टर के साथ-साथ फ़ंक्शन के लिए ओवरलोड जनरेट करेगी. हालांकि, यह डिफ़ॉल्ट वैल्यू के साथ हर पैरामीटर के लिए सिर्फ़ एक ओवरलोड बनाएगा.

आइए, UseCase.java को देखते हैं और हमारी अगली समस्या पर ध्यान देते हैं: UseCase.getSystemUsers() तरीके में user.hasSystemAccess() पर कॉल:

public static List<User> getSystemUsers() {
   ArrayList<User> systemUsers = new ArrayList<>();
   for (User user : Repository.getUsers()) {
       if (user.hasSystemAccess()) {     // Now has an error!
           systemUsers.add(user);
       }
   }
   return systemUsers;
}

यह एक दिलचस्प गड़बड़ी है! अगर आप क्लास User पर अपनी IDE' की ऑटोकंप्लीट सुविधा का इस्तेमाल करते हैं, तो आप देखेंगे कि hasSystemAccess() का नाम बदलकर getHasSystemAccess() कर दिया गया है.

समस्या को ठीक करने के लिए, हम चाहते हैं कि Kotlin val प्रॉपर्टी के लिए एक अलग नाम जनरेट करे hasSystemAccess. ऐसा करने के लिए, हम @JvmName एनोटेशन का इस्तेमाल कर सकते हैं. आइए, User.kt पर स्विच करें और देखें कि हमें इसे कहां लागू करना चाहिए.

एनोटेशन को लागू करने के दो तरीके हैं. सबसे पहले इसे get() तरीके पर सीधे लागू करें, जैसे:

val hasSystemAccess
   @JvmName("hasSystemAccess")
   get() = "sys" in groups

यह Kotlin को सिग्नल देता है, ताकि दिए गए नाम में साफ़ तौर पर तय किए गए गैटर का हस्ताक्षर बदला जा सके.

इसके अलावा, इस तरह के get: प्रीफ़िक्स का इस्तेमाल करके, प्रॉपर्टी पर लागू किया जा सकता है:

@get:JvmName("hasSystemAccess")
val hasSystemAccess
   get() = "sys" in groups

दूसरा तरीका खास तौर पर उन प्रॉपर्टी के लिए काम का है जो डिफ़ॉल्ट तौर पर, इंप्लिसिट तरीके से तय किए गए गैटर का इस्तेमाल कर रही हैं. उदाहरण के लिए:

@get:JvmName("isActive")
val active: Boolean

इससे गैटर के बारे में साफ़ तौर पर बताए बिना, गैटर का नाम बदला जा सकता है.

इस फ़र्क़ के बावजूद, आप अपने हिसाब से इनमें से किसी भी एक विकल्प का इस्तेमाल कर सकते हैं. दोनों से Kotlin नाम का hasSystemAccess() का इस्तेमाल करके गैटर बन जाएगा.

अगर हम UseCase.java पर वापस स्विच करते हैं, तो हम पुष्टि कर सकते हैं कि getSystemUsers() में अब गड़बड़ी नहीं है!

अगली गड़बड़ी formatUser() में है, लेकिन अगर आप Kotlin गैटर नाम रखने के तरीके के बारे में ज़्यादा पढ़ना चाहते हैं, तो अगले चरण पर जाने से पहले यहां पढ़ें.

गैटर और सेटर नामिंग

जब हम 'Kotlin लिखते हैं, तो यह लिखना आसान हो जाता है:

val myString = "Logged in as ${user.displayName}")

असल में, displayName का मान पाने के लिए, फ़ंक्शन को कॉल कर रहा है. हम मेन्यू में टूल > Kotlin > Kotlin बाइट कोड दिखाएं और फिर डिकोड करें बटन पर क्लिक करके इसकी पुष्टि कर सकते हैं:

String myString = "Logged in as " + user.getDisplayName();

जब हम इन Java को ऐक्सेस करना चाहते हैं, तो हमें गैटर का नाम साफ़ तौर पर लिखना होगा.

ज़्यादातर मामलों में, Kotlin प्रॉपर्टी के लिए गैटर का Java नाम, सिर्फ़ get + प्रॉपर्टी का नाम होता है, जैसा कि हम User.getHasSystemAccess() और User.getDisplayName() के साथ देखते हैं. इसका एक अपवाद वे प्रॉपर्टी है जिनके नाम "is&कोटेशन; से शुरू होते हैं. इस मामले में, गैटर के लिए Java नाम, Kotlin प्रॉपर्टी का नाम है.

उदाहरण के लिए, User पर कोई प्रॉपर्टी, जैसे:

val isAdmin get() = //...

Java से इसमें ऐक्सेस किया जाएगा:

boolean userIsAnAdmin = user.isAdmin();

@JvmName एनोटेशन का इस्तेमाल करके, Kotlin डिफ़ॉल्ट रूप से तय बाइट कोड जनरेट करता है, न कि डिफ़ॉल्ट किए गए आइटम के लिए.

यह उन सेटर के लिए भी काम करती है जिनके जनरेट किए गए नाम हमेशा set और प्रॉपर्टी का नाम होते हैं. उदाहरण के लिए, नीचे दी गई कक्षा लें:

class Color {
   var red = 0f
   var green = 0f
   var blue = 0f
}

मान लीजिए कि हम ##39;अलग करने वाले को छोड़कर, सेटर का नाम setRed() से बदलकर updateRed() कर देना चाहते हैं. ऐसा करने के लिए हम @set:JvmName वर्शन का इस्तेमाल कर सकते हैं:

class Color {
   @set:JvmName("updateRed")
   var red = 0f
   @set:JvmName("updateGreen")
   var green = 0f
   @set:JvmName("updateBlue")
   var blue = 0f
}

Java से, हम'd लिख सकते हैं:

color.updateRed(0.8f);

UseCase.formatUser(), User ऑब्जेक्ट की प्रॉपर्टी के मान पाने के लिए, सीधे फ़ील्ड ऐक्सेस का इस्तेमाल करता है.

Kotlin में, आम तौर पर प्रॉपर्टी को गैटर और सेटर के ज़रिए दिखाया जाता है. इसमें val प्रॉपर्टी शामिल हैं.

@JvmField एनोटेशन का इस्तेमाल करके, इस व्यवहार को बदला जा सकता है. अगर इसे क्लास में किसी प्रॉपर्टी पर लागू किया जाता है, तो Kotlin में var प्रॉपर्टी के लिए गैटर (और सेटर) जनरेट करना छोड़ दिया जाएगा. साथ ही, बैकिंग फ़ील्ड को सीधे ऐक्सेस किया जा सकेगा.

User ऑब्जेक्ट नहीं बदले नहीं जा सकते, इसलिए हम अपनी हर प्रॉपर्टी को फ़ील्ड के तौर पर दिखाना चाहते हैं. इसलिए, हम उनमें से हर एक की व्याख्या @JvmField से करते हैं:

data class User @JvmOverloads constructor(
   @JvmField val id: Int,
   @JvmField val username: String,
   @JvmField val displayName: String = username.toTitleCase(),
   @JvmField val groups: List<String> = listOf("guest")
) {
   @get:JvmName("hasSystemAccess")
   val hasSystemAccess
       get() = "sys" in groups
}

अगर हम UseCase.formatUser() को फिर से देखते हैं, तो देख सकते हैं कि गड़बड़ियां ठीक हो गई हैं!

@JvmField या कॉन्स्ट

इसके साथ, UseCase.java फ़ाइल में एक और मिलती-जुलती गड़बड़ी है:

Repository.saveAs(Repository.BACKUP_PATH);

अगर हम यहां अपने-आप पूरा होने की सुविधा का इस्तेमाल करते हैं, तो हम देख सकते हैं कि Repository.getBACKUP_PATH() मौजूद है. इसलिए, हो सकता है कि आप BACKUP_PATH पर एनोटेशन को @JvmStatic से बदलकर @JvmField करना चाहें.

आइए इसे आज़माएं. Repository.kt पर वापस जाएं और एनोटेशन अपडेट करें:

object Repository {
   @JvmField
   val BACKUP_PATH = "/backup/user.repo"

अगर UseCase.java को अभी देखा जाएगा, तो हमें पता चला है कि गड़बड़ी ठीक हो गई है. हालांकि, इस यूआरएल पर BACKUP_PATH का नोट भी है:

Kotlin में, सिर्फ़ const, प्रिमिटिव हो सकते हैं, जैसे कि int, float, और String. इस मामले में, क्योंकि BACKUP_PATH एक स्ट्रिंग है, इसलिए हम @JvmField की जानकारी देने वाले val के बजाय const val का इस्तेमाल करके बेहतर परफ़ॉर्मेंस पा सकते हैं. साथ ही, आप मान को फ़ील्ड के तौर पर ऐक्सेस कर सकते हैं.

Repository.kt में अब आने वाले बदलाव को बदलें:

object Repository {
   const val BACKUP_PATH = "/backup/user.repo"

अगर हम UseCase.java को फिर से देखें, तो हम देख सकते हैं कि इसमें सिर्फ़ एक गड़बड़ी है.

आखिरी गड़बड़ी Exception: 'java.io.IOException' is never thrown in the corresponding try block. बताती है

हालांकि, अगर हम Repository.kt में Repository.saveAs के कोड पर नज़र डालें, तो हमें पता चलता है कि यह एक अपवाद है. क्या समस्या है?

Java में एक "अपवाद के तौर पर सही का निशान&&t> है. इन अपवादों को वापस लाया जा सकता है, जैसे कि उपयोगकर्ता ने फ़ाइल का नाम गलत लिख दिया हो या नेटवर्क कुछ समय के लिए उपलब्ध न हो. जांच के बाद आने वाले किसी अपवाद के पता चलने पर, डेवलपर उपयोगकर्ता को सुझाव दे सकता है कि समस्या को कैसे ठीक करना है.

कंपाइल किए गए समय पर जांचे गए अपवादों की जांच की जाती है, इसलिए आप उन्हें मेथड' के हस्ताक्षर में बताते हैं:

public void openFile(File file) throws FileNotFoundException {
   // ...
}

दूसरी ओर, Kotlin में चेक किए गए अपवाद नहीं होते और वह यहां #39; समस्या किस वजह से होती है.

इसका हल, Kotlin को IOException वह और #39;, Repository.saveAs() के हस्ताक्षर में जोड़ने के लिए कहना है, ताकि जेवीएम बाइटकोड में यह चेक किए गए अपवाद के तौर पर शामिल हो.

हम Kotlin @Throws एनोटेशन के साथ ऐसा करते हैं. इससे Java/Kotlin की इंटरोऑपरेबिलिटी (दूसरे सिस्टम के साथ काम करना) में मदद मिलती है. Kotlin में, अपवाद Java की तरह काम करते हैं, लेकिन Java से अलग, Kotlin में सिर्फ़ सही के निशान वाले अपवाद हैं. इसलिए, अगर आप अपने Java कोड को यह बताना चाहते हैं कि कोई Kotlin फ़ंक्शन एक अपवाद देता है, तो आपको नया एनोटेशन शामिल करने के लिए, Kotlin फ़ंक्शन सिग्नेचर स्विच में @Throws एनोटेशन का इस्तेमाल करना होगा, Repository.kt file और saveAs() को अपडेट करना होगा:

@JvmStatic
@Throws(IOException::class)
fun saveAs(path: String?) {
   val outputFile = File(path)
   if (!outputFile.canWrite()) {
       throw FileNotFoundException("Could not write to file: $path")
   }
   // Write data...
}

@Throws एनोटेशन की मदद से, यह देखा जा सकता है कि UseCase.java में कंपाइलर से जुड़ी सभी गड़बड़ियां ठीक कर ली गई हैं! बहुत बढ़िया!

शायद आप यह सोच सकें कि अब आपको Kotlin से saveAs() को कॉल करने पर, try और catch ब्लॉक करने होंगे.

नहीं! याद रखें, Kotlin में अपवादों की जांच नहीं की गई है. साथ ही, किसी तरीके में @Throws जोड़ने से उसे बदला नहीं जाता:

fun saveFromKotlin(path: String) {
   Repository.saveAs(path)
}

अपवादों को समझने में अब भी #39 मदद कर सकते हैं, लेकिन जब तक Kotlin को उन्हें हैंडल करने के लिए मजबूर नहीं किया जाता, तब तक Kotlin में इनका इस्तेमाल किया जा सकता है.

इस कोडलैब में, हमने Kotlin कोड लिखने की उन बुनियादी बातों के बारे में बताया है जो मुहावरों को Java कोड लिखने की सुविधा देती हैं.

हमने बताया कि हम Kotlin को अपने JVM बाइट कोड को जनरेट करने के तरीके को बदलने के लिए एनोटेशन का इस्तेमाल कैसे कर सकते हैं, जैसे:

  • स्टैटिक सदस्यों और तरीकों को जनरेट करने के लिए, @JvmStatic.
  • @JvmOverloads डिफ़ॉल्ट फ़ंक्शन वाले फ़ंक्शन के लिए ओवरलोड होने वाले तरीके जनरेट कर सकते हैं.
  • गैटर और सेटर का नाम बदलने के लिए @JvmName.
  • @JvmField प्रॉपर्टी को गैटर और सेटर के बजाय, सीधे फ़ील्ड के तौर पर दिखाना.
  • अपवादों के बारे में बताने के लिए @Throws.

हमारी फ़ाइलों का फ़ाइनल कॉन्टेंट है:

User.kt

data class User @JvmOverloads constructor(
   @JvmField val id: Int,
   @JvmField val username: String,
   @JvmField val displayName: String = username.toTitleCase(),
   @JvmField val groups: List<String> = listOf("guest")
) {
   val hasSystemAccess
       @JvmName("hasSystemAccess")
       get() = "sys" in groups
}

Repository.kt

object Repository {
   const val BACKUP_PATH = "/backup/user.repo"

   private val _users = mutableListOf<User>()
   private var _nextGuestId = 1000

   @JvmStatic
   val users: List<User>
       get() = _users

   @JvmStatic
   val nextGuestId
       get() = _nextGuestId++

   init {
       _users.add(User(100, "josh", "Joshua Calvert", listOf("admin", "staff", "sys")))
       _users.add(User(101, "dahybi", "Dahybi Yadev", listOf("staff", "nodes")))
       _users.add(User(102, "sarha", "Sarha Mitcham", listOf("admin", "staff", "sys")))
       _users.add(User(103, "warlow", groups = listOf("staff", "inactive")))
   }

   @JvmStatic
   @Throws(IOException::class)
   fun saveAs(path: String?):Boolean {
       val backupPath = path ?: return false

       val outputFile = File(backupPath)
       if (!outputFile.canWrite()) {
           throw FileNotFoundException("Could not write to file: $backupPath")
       }
       // Write data...
       return true
   }

   @JvmStatic
   fun addUser(user: User) {
       // Ensure the user isn't already in the collection.
       val existingUser = users.find { user.id == it.id }
       existingUser?.let { _users.remove(it) }
       // Add the user.
       _users.add(user)
   }
}

स्ट्रिंगUtils.kt

@file:JvmName("StringUtils")

package com.google.example.javafriendlykotlin

fun String.toTitleCase(): String {
   if (isNullOrBlank()) {
       return this
   }

   return split(" ").map { word ->
       word.foldIndexed("") { index, working, char ->
           val nextChar = if (index == 0) char.toUpperCase() else char.toLowerCase()
           "$working$nextChar"
       }
   }.reduceIndexed { index, working, word ->
       if (index > 0) "$working $word" else word
   }
}

fun String.nameToLogin(): String {
   if (isNullOrBlank()) {
       return this
   }
   var working = ""
   toCharArray().forEach { char ->
       if (char.isLetterOrDigit()) {
           working += char.toLowerCase()
       } else if (char.isWhitespace() and !working.endsWith(".")) {
           working += "."
       }
   }
   return working
}