Bu doküman, Java ve Kotlin'de herkese açık API'ler yazmaya yönelik bir kural grubudur bu kodu kullanabilirsiniz. Bunun amacı, kodun diğer dili'ne dokunun.
Java (Kotlin tüketimi için)
Sabit anahtar kelime yok
Yöntem adı olarak Kotlin'in katı anahtar kelimelerinden hiçbirini kullanmayın girin. Bunlar, Kotlin. Geçici anahtar kelimeler, değiştirici anahtar kelimeler ve özel tanımlayıcılara izin verilir.
Örneğin, Mockito'nun when
işlevi, Kotlin'den kullanıldığında vurgu işareti gerektirir:
val callable = Mockito.mock(Callable::class.java)
Mockito.`when`(callable.call()).thenReturn(/* … */)
Any
uzantı adından kaçının
Şu URL'ler için Any
eklentisindeki uzantı işlevlerinin adlarını kullanmaktan kaçının:
yöntemlerini veya Any
eklentisindeki uzantı özelliklerinin adlarını
alanlarına girmenizi öneririz. Üye yöntemleri ve alanları her zaman
Any
uzantılı işlevlere veya özelliklerine göre öncelikliyse
olduğunu anlamak zor olabilir.
Boş değer atanabilirlik ek açıklamaları
Genel bir API'deki primitif olmayan her parametre, döndürme ve alan türü değer atanabilirlik ek açıklamasına sahip. Ek açıklaması olmayan türler, "platform" türler olarak ayarlanmıştır.
Varsayılan olarak, Kotlin derleyici işaretleri JSR 305 ek açıklamalarını dikkate alır ancak işaretler uyarı içeriyor. Ayrıca, derleyicinin ek açıklamaları hata olarak gösterir.
Lambda parametreleri sonuncu
SAM dönüşümü için uygun parametre türleri "son" olmalıdır.
Örneğin, RxJava 2'nin Flowable.create()
yöntem imzası şu şekilde tanımlanır:
public static <T> Flowable<T> create(
FlowableOnSubscribe<T> source,
BackpressureStrategy mode) { /* … */ }
FlowableOnChannel, SAM dönüşümü için uygun olduğundan Kotlin'deki bu yöntem aşağıdaki gibi görünür:
Flowable.create({ /* … */ }, BackpressureStrategy.LATEST)
Ancak parametreler yöntem imzasında ters çevrildiyse fonksiyon şöyle bir tercihte bulunacağız:
Flowable.create(BackpressureStrategy.LATEST) { /* … */ }
Mülk önekleri
Bir yöntemin Kotlin'de özellik olarak temsil edilmesi için katı "fasulye" stili önek kullanılmalıdır.
Erişimci yöntemleri, get
öneki veya boole döndüren yöntemler için is
gerektirir
ön eki kullanılabilir.
public final class User {
public String getName() { /* … */ }
public boolean isActive() { /* … */ }
}
val name = user.name // Invokes user.getName()
val active = user.isActive // Invokes user.isActive()
İlişkilendirilmiş mutatör yöntemleri için set
öneki gerekir.
public final class User {
public String getName() { /* … */ }
public void setName(String name) { /* … */ }
public boolean isActive() { /* … */ }
public void setActive(boolean active) { /* … */ }
}
user.name = "Bob" // Invokes user.setName(String)
user.isActive = true // Invokes user.setActive(boolean)
Yöntemlerin özellik olarak gösterilmesini istiyorsanız
has
, set
veya get
olmayan önekli erişimciler. Standart olmayan ön ekler içeren yöntemler
işlevi olarak çağrılabilir; Bunlar, işleve bağlı olarak
yöntemidir.
Operatör aşırı yüklemesi
Özel çağrı-site söz dizimine izin veren yöntem adlarına (ör. operatör aşırı yüklemesi). Yöntemin kısaltılmış söz dizimiyle kullanılması mantıklıdır.
public final class IntBox {
private final int value;
public IntBox(int value) {
this.value = value;
}
public IntBox plus(IntBox other) {
return new IntBox(value + other.value);
}
}
val one = IntBox(1)
val two = IntBox(2)
val three = one + two // Invokes one.plus(two)
Kotlin (Java tüketimi için)
Dosya adı
Bir dosya üst düzey işlevler veya özellikler içerdiğinde her zaman ek açıklama ekleyin
güzel bir ad için @file:JvmName("Foo")
ile değiştirin.
Varsayılan olarak, MyClass.kt dosyasındaki en üst düzey üyeler,
MyClassKt
, uygun değildir ve uygulama sırasında dili sızdırır
bolca fırsat sunuyor.
Şu gruptaki üst düzey üyeleri birleştirmek için @file:JvmMultifileClass
ekleyin:
tek sınıfa dönüştürmenizi sağlar.
Lambda bağımsız değişkenleri
Java'da tanımlanan tek yöntem arayüzleri (SAM) hem Kotlin'de uygulanabilir lambda söz dizimini kullanarak Java ve Java sağlar. Kotlin, bu tür arayüzleri tanımlamak için kullanabileceğiniz çeşitli seçeneklere sahiptir. Bu seçeneklerin her birinde farkına varır.
Tercih edilen tanım
Java'dan kullanılması amaçlanan daha üst düzey işlevler
Unit
değerini döndüren işlev türlerini
Java arayanlarının Unit.INSTANCE
döndürmesini gerektirir. Fonksiyonu satır içine almak yerine
İmzayı yazmak için işlevsel (SAM) arayüzleri kullanın. Ayrıca
normal arayüzler yerine işlevsel (SAM) arayüzler kullanmayı düşünün
lambda olarak kullanılması beklenen arayüzleri tanımlarken kullanılan arayüzler
Bu, Kotlin'in deyimsel kullanımına olanak tanır.
Şu Kotlin tanımına bakın:
fun interface GreeterCallback {
fun greetName(String name)
}
fun sayHi(greeter: GreeterCallback) = /* … */
Kotlin'den çağrıldığında:
sayHi { println("Hello, $it!") }
Java'dan çağrıldığında:
sayHi(name -> System.out.println("Hello, " + name + "!"));
İşlev türü bir Unit
döndürmese bile iyi bir değer olabilir
arayanların bunu adlandırılmış bir
sınıfını da (hem lambdas hem de Kotlin ve Java'da) kapsar.
class MyGreeterCallback : GreeterCallback {
override fun greetName(name: String) {
println("Hello, $name!");
}
}
Unit
değerini döndüren işlev türlerini kullanmaktan kaçının
Şu Kotlin tanımına bakın:
fun sayHi(greeter: (String) -> Unit) = /* … */
Java arayanlarının Unit.INSTANCE
döndürmesini gerektirir:
sayHi(name -> {
System.out.println("Hello, " + name + "!");
return Unit.INSTANCE;
});
Uygulamanın, durum bilgisi içereceği durumlarda işlevsel arayüzler kullanmaktan kaçının
Arayüz uygulamasının bir durum içermesi istendiğinde lambda
söz dizimi mantıklı değil. Karşılaştırılabilir, bunun önemli bir örneğidir.
this
ile other
karşılaştırması yapıldığından ve lambdalarda this
yok. Değil
arayüzün fun
önekiyle eklenmesi çağrıyı object : ...
kullanmaya zorlar
söz dizimini kullanır. Bu, duruma sahip olmasına olanak tanıyarak arayana bir ipucu sağlar.
Şu Kotlin tanımına bakın:
// No "fun" prefix.
interface Counter {
fun increment()
}
Kotlin'de lambda söz dizimini engeller ve şu daha uzun sürümü gerektirir:
runCounter(object : Counter {
private var increments = 0 // State
override fun increment() {
increments++
}
})
Nothing
genel anahtar kelime kullanmaktan kaçının
Genel parametresi Nothing
olan bir tür, Java'ya ham tür olarak sunulur. Çiğ
türleri Java'da nadiren kullanılır ve bundan kaçınılmalıdır.
Doküman istisnaları
İşaretli istisnalar atabilen işlevler, bunları
@Throws
Çalışma zamanı istisnaları KDoc'ta belgelenmelidir.
Bir işlevin yetki verdiği API'lere dikkat edin, çünkü bu API'ler kontrol edilmiş olabilir Ancak bu istisnalar geçerli olabilir.
Savunma kopyaları
Herkese açık API'lerden paylaşılan veya sahip olunmayan koleksiyonları döndürürken sarmala bunları değiştirilemez bir kapsayıcıda saklama veya savunma amaçlı kopyalama yapma. Kotlin'e rağmen salt okunur özelliklerini zorunlu kılmak için yanı sıra. Sarmalayıcı veya savunma amaçlı kopya olmadan, değişmeyen değerler uzun ömürlü bir koleksiyon referansı döndürme
Tamamlayıcı işlevleri
Tamamlayıcı nesnedeki herkese açık işlevlere @JvmStatic
ile ek açıklama eklenmelidir
ele alacağız.
Ek açıklama olmadan, bu işlevler yalnızca örnek yöntemi olarak kullanılabilir
statik Companion
alanında çalışır.
Yanlış: Ek açıklama yok
class KotlinClass {
companion object {
fun doWork() {
/* … */
}
}
}
public final class JavaClass {
public static void main(String... args) {
KotlinClass.Companion.doWork();
}
}
Doğru: @JvmStatic
not
class KotlinClass {
companion object {
@JvmStatic fun doWork() {
/* … */
}
}
}
public final class JavaClass {
public static void main(String... args) {
KotlinClass.doWork();
}
}
Tamamlayıcı sabit değerler
companion
object
içinde etkili sabit değerler olan, const
olmayan herkese açık mülklerin statik alan olarak kullanıma sunulması için @JvmField
ile not eklenmesi gerekir.
Ek açıklama olmadığında bu özellikler yalnızca garip şekilde adlandırılmış olabilir.
örnek "alıcılar" Companion
değerini alır. Bunun yerine @JvmStatic
kullanılıyor
/@JvmField
, garip isimdeki "alıcılar" işlemini taşıyor statik yöntemlerden biriyle
Bu yine de yanlıştır.
Yanlış: Ek açıklama yok
class KotlinClass {
companion object {
const val INTEGER_ONE = 1
val BIG_INTEGER_ONE = BigInteger.ONE
}
}
public final class JavaClass {
public static void main(String... args) {
System.out.println(KotlinClass.INTEGER_ONE);
System.out.println(KotlinClass.Companion.getBIG_INTEGER_ONE());
}
}
Yanlış: @JvmStatic
not
class KotlinClass {
companion object {
const val INTEGER_ONE = 1
@JvmStatic val BIG_INTEGER_ONE = BigInteger.ONE
}
}
public final class JavaClass {
public static void main(String... args) {
System.out.println(KotlinClass.INTEGER_ONE);
System.out.println(KotlinClass.getBIG_INTEGER_ONE());
}
}
Doğru: @JvmField
not
class KotlinClass {
companion object {
const val INTEGER_ONE = 1
@JvmField val BIG_INTEGER_ONE = BigInteger.ONE
}
}
public final class JavaClass {
public static void main(String... args) {
System.out.println(KotlinClass.INTEGER_ONE);
System.out.println(KotlinClass.BIG_INTEGER_ONE);
}
}
Deyimsel adlandırma
Kotlin'in Java'dan farklı çağrı kuralları vardır ve bu kurallar
Ad işlevleri. Deyimsel olacak şekilde adlar tasarlamak için @JvmName
kullanın
her iki dilin kurallarını kullanabilir veya ilgili standart kitaplıkların
eşleşmesini sağlayabilirsiniz.
adlandırabilirsiniz.
Bu durum en sık uzantı işlevleri ve uzantı özelliklerinde görülür. çünkü alıcı türünün konumu farklı.
sealed class Optional<T : Any>
data class Some<T : Any>(val value: T): Optional<T>()
object None : Optional<Nothing>()
@JvmName("ofNullable")
fun <T> T?.asOptional() = if (this == null) None else Some(this)
// FROM KOTLIN:
fun main(vararg args: String) {
val nullableString: String? = "foo"
val optionalString = nullableString.asOptional()
}
// FROM JAVA:
public static void main(String... args) {
String nullableString = "Foo";
Optional<String> optionalString =
Optionals.ofNullable(nullableString);
}
Varsayılanlar için işlev aşırı yüklemeleri
Varsayılan değeri olan parametrelere sahip işlevler @JvmOverloads
kullanmalıdır.
Bu ek açıklama olmadan,
varsayılan değerlere sahiptir.
@JvmOverloads
kullanırken oluşturulan yöntemleri inceleyerek her birinin
mantıklı olabilir. Uymuyorsa aşağıdaki yeniden düzenleme işlemlerinin birini veya ikisini birden yapın
memnun kalana kadar:
- Parametre sırasını, varsayılanları en düşük olanları tercih edecek şekilde değiştirin. dokunun.
- Varsayılan değerleri, manuel işlev aşırı yüklemelerine taşıyın.
Yanlış: Hayır @JvmOverloads
class Greeting {
fun sayHello(prefix: String = "Mr.", name: String) {
println("Hello, $prefix $name")
}
}
public class JavaClass {
public static void main(String... args) {
Greeting greeting = new Greeting();
greeting.sayHello("Mr.", "Bob");
}
}
Doğru: @JvmOverloads
not.
class Greeting {
@JvmOverloads
fun sayHello(prefix: String = "Mr.", name: String) {
println("Hello, $prefix $name")
}
}
public class JavaClass {
public static void main(String... args) {
Greeting greeting = new Greeting();
greeting.sayHello("Bob");
}
}
Tiftik Kontrolleri
Gereksinimler
- Android Studio sürümü: 3.2 Canary 10 veya sonraki sürümler
- Android Gradle Eklentisi sürümü: 3.2 veya üzeri
Desteklenen Kontroller
Artık bu hatalardan bazılarını tespit edip işaretlemenize yardımcı olacak Android Lint kontrolleri var. Daha önce açıklanan birlikte çalışabilirlik sorunları. Yalnızca Java'daki sorunlar (Kotlin için tüketim) tespit edilir. Özellikle, desteklenen kontroller şunlardır:
- Bilinmeyen Boşluk
- Mülk Erişimi
- Hard Kotlin anahtar kelimesi yok
- Lambda Parametreleri En Son
Android Studio
Bu kontrolleri etkinleştirmek için Dosya > Tercihler > Düzenleyici > Denetimler ve Kotlin Interoperability altında etkinleştirmek istediğiniz kuralları işaretleyin:
Şekil 1. Android Studio'daki Kotlin birlikte çalışabilirlik ayarları.
Etkinleştirmek istediğiniz kuralları kontrol ettikten sonra yeni kontroller kod incelemelerinizi çalıştırdığınızda çalıştırma (Analiz > Kodu İncele...)
Komut satırı derlemeleri
Bu kontrolleri komut satırı derlemelerinden etkinleştirmek için aşağıdaki satırı
build.gradle
dosyanız:
Eski
android { ... lintOptions { enable 'Interoperability' } }
Kotlin
android { ... lintOptions { enable("Interoperability") } }
lintOptions içinde desteklenen yapılandırmaların tamamı için Android Gradle DSL referansı.
Ardından komut satırından ./gradlew lint
komutunu çalıştırın.