Kotlin 1.5.0-RC: Standart ve Test Kütüphanelerindeki Değişiklikler

Kotlin'nin yeni versiyonu, 1.5.0-RC yayınlandı. Bu yeni versiyon ile gelen değişiklere bir göz atalım.

Görsel Referansı


Stabil Unsigned Tam Sayı Türleri


Standart kütüphane, negatif olmayan tam sayı işlemleriyle uğraşmak için yararlı olan unsigned tamsayı API'sini içerir:

  • Unsigned numara türleri: UInt, ULong, UByte, UShort ve dönüşümler gibi ilgili işlevler.

  • Toplama türleri: İşaretsiz tam sayıların dizileri, aralıkları ve ilerlemeleri: UIntArray, UIntRange ve diğer türler için benzer container'lar.

Unsigned tam sayı türleri, Kotlin 1.3'ten beri Beta'da mevcut durumda bulunuyor. Şimdi, unsigned tam sayı türleri ve işlemleri kararlı olarak sınıflandırılarak, gerçek hayattaki projelerde kullanmak için tercihe bağlı olmadan kullanılabilir ve güvenli hale getiriliyor.


Yani, yeni kararlı API'ler; unsigned tam sayı türleri, unsigned tam sayı türlerinin aralıkları ve ilerlemeleri unsigned tam sayı türleriyle çalışan işlevler oluyor.

val zero = 0U // Define unsigned numbers with literal suffixes
val ten = 10.toUInt() // or by converting non-negative signed numbers
//val minusOne: UInt = -1U // Error: unary minus is not defined
val range: UIntRange = zero..ten // Separate types for ranges and progressions

for (i in range) print(i)
println()
println("UInt covers the range from ${UInt.MIN_VALUE} to ${UInt.MAX_VALUE}") // UInt covers the range from 0 to 4294967295

Java.nio.file.Path İçin Uzantılar


Kotlin, java.nio.file.Path için uzantı işlevleri aracılığıyla, modern engellemesiz Java IO'yu Kotlin deyimsel bir tarzda kullanmanın bir yolunu sunuyor.

import kotlin.io.path.*
import java.nio.file.Path

fun main() {
    // construct path with the div (/) operator
    val baseDir = Path("/base")
    val subDir = baseDir / "subdirectory"

    // list files in a directory
    val kotlinFiles = Path("/home/user").listDirectoryEntries("*.kt")
    // count lines in all kotlin files
    val totalLines = kotlinFiles.sumOf { file -> file.useLines { lines -> lines.count() } }
}

Bu uzantılar, Kotlin 1.4.20'de deneysel bir özellik olarak tanıtıldı ve artık bir isteğe bağlı olmaksızın kullanılabiliyor. Kullanabileceğiniz işlevlerin listesi için kotlin.io.path paketine bakabilirsiniz.


Büyük ve Küçük Harf İçin Yerel Dil Ayarından Bağımsız API


Birçoğunuz dizelerin ve karakterlerin durumunu değiştirmek için stdlib işlevlerini biliyorsunuz: toUpperCase(), toLowerCase(), toTitleCase(). Genellikle iyi çalışıyorlar ancak farklı platform yerel dil ayarları söz konusu olduğunda baş ağrısına neden olabiliyor - hepsi yerel duyarlı, bu da sonuçlarının yerel dil ayarına bağlı olarak farklılık gösterebileceği anlamına geliyor. Örneğin, "Kotlin" .toUpperCase () ne döndürür? Açıkçası KOTLIN diyorsunuz. Ama Türkçe'de büyük harfte İ, yani sonuç farklı: KOTLİN.


Artık dizelerin ve karakterlerin durumunu değiştirmek için yeni bir yerel dil ayarından bağımsız API var: büyük harf(), küçük harf(), titlecase() uzantıları ve bunların * Char() karşılıkları. v1.4.30'da ön izlemesini zaten denemiş olabilirsiniz.

// replace the old API
println("Kotlin".toUpperCase()) // KOTLIN or KOTLİN or?..

// with the new API
println("Kotlin".uppercase()) // Always KOTLIN

JVM'de, yeni işlevleri bağımsız değişken olarak geçerli yerel dil ayarı ile çağırarak yerel dil ayarına duyarlı büyük/küçük harf değişimi gerçekleştirebilirsiniz:

"Kotlin".uppercase(Locale.getDefault()) // Locale-sensitive uppercasing

Char-to-code ve Char-to-digit Dönüşümlerini Temizlemek


Bir karakterin UTF-16 kodunu alma işlemi - toInt() işlevi - yaygın bir tuzaktı çünkü bu rakamla sunulan bir Int üreten tek basamaklı dizelerde String.toInt() 'e oldukça benziyor.

"4".toInt() // returns 4
'4'.toInt() // returns 52

Ek olarak, Char '4' için 4 sayısal değerini döndürecek ortak bir işlev yoktu.


Bu sorunları çözmek için artık karakterler ve bunların tam sayı kodları ve sayısal değerleri arasında dönüşüm için bir dizi yeni işlev bulunuyor:

  • Char (code) ve Char.code, bir karakter ve kodu arasında dönüştürülür.

  • Char.digitToInt(radix: Int) ve * OrNull sürümü, belirtilen tabandaki bir rakamdan bir tam sayı oluşturur.

  • Int.digitToChar(radix: Int), belirtilen tabandaki bir tam sayıyı temsil eden bir rakamdan bir karakter oluşturur.

Bu işlevlerin açık adları vardır ve kodu daha okunaklı hale getirir:

val capsK = Char(75) // ‘K’
val one = '1'.digitToInt(10) // 1
val digitC = 12.digitToChar(16) // hexadecimal digit ‘C’

println("${capsK}otlin ${one}.5.0-R${digitC}") // “Kotlin 1.5.0-RC”
println(capsK.code) // 75

Yeni işlevler ön izleme modunda Kotlin 1.4.30'dan beri mevcuttu ve artık kararlı olarak bulunuyor. Karakterden sayıya dönüştürme için eski işlevler (Char.toInt() ve diğer sayısal türler için benzer işlevler) ve sayıdan karaktere dönüştürme (Long.toChar() ve Int.toChar() hariç benzerleri) artık kullanımdan kaldırılmıştır.


Genişletilmiş Çoklu Platform Sohbet API'si


Kotlin bir dizi Char işlevini kullanıma sundu. Bu işlevler şunlardır:

  • Bir karakterin harf mi yoksa rakam mı olduğunu kontrol eden Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit().

  • Bir karakterin durumunu kontrol eden Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase().

  • Bir karakterin Cn (tanımsız) dışında bir Unicode genel kategorisine sahip olup olmadığını kontrol eden Char.isDefined().

  • Char.isISOControl(), bir karakterin \ u0000 .. \ u001F veya \ u007F .. \ u009F aralığında bir koda sahip bir ISO kontrol karakteri olup olmadığını kontrol eder.

Bir karakterin Unicode'a göre genel kategorisini belirten Char.category ve dönüş türü enum sınıfı Char Category özelliği artık çoklu platform projelerinde mevcuttur.

val array = "Kotlin 1.5.0-RC".toCharArray()
val (letterOrDigit, punctuation) = array.partition { it.isLetterOrDigit() }
val (upperCase, notUpperCase ) = array.partition { it.isUpperCase() }

println("$letterOrDigit, $punctuation") // [K, o, t, l, i, n, 1, 5, 0, R, C], [ , ., ., -]
println("$upperCase, $notUpperCase") // [K, R, C], [o, t, l, i, n, , 1, ., 5, ., 0, -]

if (array[0].isDefined()) println(array[0].category)


String?.ToBoolean()'ın Sürümleri


Kotlin’in String?.ToBoolean() işlevi, String'lerden boolean değerleri oluşturmak için yaygın olarak kullanılıyor. Oldukça basit çalışıyor: durumu ne olursa olsun bir String "true"'da true ve null dahil olmak üzere diğer tüm String'lerde false.


Bu davranış doğal görünmekle birlikte, potansiyel olarak hatalı durumları gizleyebiliyor. Bu işlevle ne dönüştürürseniz dönüştürün, dizede beklenmedik bir değer olsa bile bir boolean elde edersiniz.


String?.ToBoolean() öğesinin büyük/küçük harfe duyarlı yeni sürümleri, bu tür hataları önlemeye yardımcı olmak için buradadır:


  • String.toBooleanStrict(), "true" ve "false" değişmez değerleri dışındaki tüm girdiler için bir exception atar.

  • String.toBooleanStrictOrNull(), "true" ve "false" değişmez değerleri dışındaki tüm girdiler için null döndürür.

println("true".toBooleanStrict()) // True
// println("1".toBooleanStrict()) // Exception
println("1".toBooleanStrictOrNull()) // null
println("True".toBooleanStrictOrNull()) // null: the function is case-sensitive

Duration API Değişiklikleri


Deneysel süre ve zaman ölçüm API'si 1.3.50 sürümünden beri stdlib'de mevcuttu. Bu API, zaman aralıklarının hassas ölçümü için bir API sunuyor.


Bu API'nin temel sınıflarından biri Duration'dır. İki zaman anı arasındaki süreyi temsil ediyor. 1.5.0'da, Duration hem API'de hem de dahili sunumda önemli değişiklikler alıyor.


Duration artık dahili gösterim için Double yerine bir Long değeri kullanıyor. Uzun değerler aralığı, nanosaniye hassasiyetiyle yüz yıldan fazla veya milisaniye hassasiyetle yüz milyon yılı temsil etmeyi sağlıyor. Ancak, önceden desteklenen nanosaniye altı süreler artık mevcut durumda bulunmuyor.


Çeşitli zaman birimleri için kullanılabiliyorlar: Duration.inWholeMinutes, Duration.inWholeSeconds ve diğerleri. Bu işlevler, Duration.inMinutes gibi Double tabanlı özelliklerin yerini almaya geliyor.


Diğer bir değişiklik, tam sayı değerlerinden Duration örnekleri oluşturmak için bir dizi yeni fabrika işlevidir. Doğrudan Duration türünde tanımlanıyorlar ve Int. Saniye gibi sayısal türlerin eski uzantı özelliklerini değiştiriyorlar.

import kotlin.time.ExperimentalTime
import kotlin.time.Duration

@ExperimentalTime
fun main() {
    val duration = Duration.milliseconds(120000)
    println("There are ${duration.inWholeSeconds} seconds in ${duration.inWholeMinutes} minutes")}

Matematik İşlemleri: Yuvarlanmış Bölme ve Mod Operatörü


Kotlin'de, tam sayılar üzerindeki bölme operatörü (/), sonucun kesirli kısmını düşüren kesilmiş bölümü temsil ediyor. Modüler aritmetikte, sonucu aşağıya yuvarlayan (daha küçük tam sayıya doğru), negatif sayılarda farklı bir sonuç üreten alternatif bir tabana bölünmüş bölüm de bulunuyor.


Önceden, yuvarlanmış bölme aşağıdaki gibi özel bir işlev gerektiriyordu:

fun floorDivision(i: Int, j: Int): Int {
    var result = i / j
    if (i != 0 && result <= 0) result--
    return result}
println("Truncated division -5/3: ${-5 / 3}")
println("Floored division -5/3: ${(-5).floorDiv(3)}")

Kotlin’in rem()'den (veya% operatöründen) farklıdır. Modülüs, a ve a. FloorDiv (b) * b arasındaki farktır. Sıfır olmayan modül her zaman b ile aynı işarete sahipken, a% b farklı bir işarete sahip olabilir. Bu, örneğin döngüsel listeleri uygularken yararlı olabilir:

fun getNextIndexCyclic(current: Int, size: Int ) = (current + 1).mod(size)
fun getPreviousIndexCyclic(current: Int, size: Int ) = (current - 1).mod(size)
// unlike %, mod() produces the expected non-negative value even if (current - 1) is less than 0

val size = 5
for (i in 0..(size * 2)) print(getNextIndexCyclic(i, size))
println()
for (i in 0..(size * 2)) print(getPreviousIndexCyclic(i, size))


Collections: firstNotNullOf() and firstNotNullOfOrNull()


Kotlin Collections API, yerleşik işlevlere sahip koleksiyonlar üzerindeki bir dizi popüler işlemi kapsıyor. Yaygın olmayan durumlarda, genellikle bu işlevlerin çağrılarını birleştiriyorsunuz.


Örneğin, koleksiyon öğelerinde bir seçici işlevin boş olmayan ilk sonucunu almak için, mapNotNull() ve first() öğesini çağırabilirsiniz. 1.5.0'da, bunu firstNotNullOf() yeni bir işlevin tek bir çağrısında yapabilirsiniz. FirstNotNullOf() ile birlikte, döndürülecek bir değer yoksa null üreten * veya Null() karşılığını eklenmiş.


İşte kodunuzu nasıl kısaltabileceğine dair bir örnek.


Boş değer atanabilir özelliğe sahip bir sınıfınız olduğunu ve sınıf örnekleri listesinden onun ilk boş olmayan değerine ihtiyacınız olduğunu varsayalım.

class Item(val name: String?)

Bunu, koleksiyonu yineleyerek ve bir özelliğin boş olup olmadığını kontrol ederek uygulayabilirsiniz:

// Option 1: manual implementation
for (element in collection) {
    val itemName = element.name
    if (itemName != null) return itemName
}
return null

Diğer bir yol, önceden var olan mapNotNull() ve firstOrNull() işlevlerini kullanmaktır. MapNotNull() uygulamasının, özellikle büyük koleksiyonlar için ek bellek gerektiren bir ara koleksiyon oluşturduğunu unutmayın ve bu nedenle, burada bir diziye dönüşüm de gerekli olabilir.

// Option 2: old stdlib functions
return collection
    // .asSequence() // Avoid creating intermediate list for big collections
    .mapNotNull { it.name }
    .firstOrNull()

Yeni fonksiyonda şöyle görünüyor:

// Option 3: new firstNotNullOfOrNull()
return collection.firstNotNullOfOrNull { it.name }


Test Kütüphanesi Değişiklikleri Hakkında


Yeni gelen özellikler:

  • Çoklu platform projelerinde tek Kotlin testi bağımlılığı.

  • Kotlin/JVM kaynak kümeleri için bir test çerçevesinin otomatik seçimi.

  • Onaylama işlevi güncellemeleri.


Çoklu platform projelerinde kotlin-test bağımlılığı


Artık eklemeniz gereken tek şey, ortak test kaynak kümesindeki kotlin-test bağımlılığıdır. Gradle eklentisi, diğer kaynak kümeleri için karşılık gelen platform bağımlılığını çıkaracaktır:

  • JVM kaynak kümeleri için kotlin-test-junit. Açıkça etkinleştirirseniz, kotlin-test-junit-5 veya kotlin-test-testng'e de geçebilirsiniz.

  • Kotlin/JS kaynak kümeleri için kotlin-test-js.

  • Ortak kaynak kümeleri için kotlin-test-common ve kotlin-test-annotations-common.

  • Kotlin/Native kaynak kümeleri için fazladan yapı yoktur çünkü Kotlin/Native, kotlin-test API'sinin yerleşik uygulamalarını sağlar.


Kotlin/JVM kaynak kümeleri için bir test çerçevesinin otomatik seçimi


Yukarıda açıklandığı gibi ortak test kaynağı kümesinde kotlin-test bağımlılığını belirlediğinizde, JVM kaynak kümeleri otomatik olarak JUnit 4'e bağımlılığı alır.


Groovy DSL'de şöyle görünüyor:

kotlin {
    sourceSets {
        commonTest {
            dependencies {
                 // This brings the dependency
                // on JUnit 4 transitively
                implementation kotlin('test')
            }
        }
    }
}

Ve Kotlin DSL'de:

kotlin {
    sourceSets {
        val commonTest by getting {
            dependencies {
                // This brings the dependency
                // on JUnit 4 transitively
                implementation(kotlin("test"))
            }
        }
    }
}

JUnit 5 veya TestNG'ye yalnızca test görevinde bir işlevi çağırarak da geçebilirsiniz: useJUnitPlatform() veya useTestNG()

kotlin {
    jvm {
        testRuns["test"].executionTask.configure {
            // enable TestNG support
            useTestNG()
            // or
            // enable JUnit Platform (a.k.a. JUnit 5) support
            useJUnitPlatform()
        }
    }
}

Aynı durum, kotlin-test bağımlılığını eklediğinizde yalnızca JVM projelerinde çalışır.


Onaylama işlevleri güncellemeleri


Yeni işlevlere hızlıca bir göz atalım:

  • assertIs <T>() ve assertIsNot <T>() değerin türünü kontrol edin.

  • assertContentEquals() diziler, diziler ve herhangi bir yinelenebilir için kapsayıcı içeriğini karşılaştırıyor. Daha doğrusu, beklenen ve fiili aynı öğeleri aynı sırada içerip içermediğini kontrol ediyor.

  • Double ve Float için assertEquals() ve assertNotEquals(), üçüncü bir parametre olan duyarlık ile yeni aşırı yüklemelere sahiptir.

  • assertContains(), contains() operatörü tanımlı herhangi bir nesnede bir öğenin varlığını kontrol ediyor: dizi, liste, aralık vb.

İşte bu işlevlerin kullanımını gösteren kısa bir örnek:

@Test
fun test() {
    val expectedArray = arrayOf(1, 2, 3)
    val actualArray = Array(3) { it + 1 }
    
    val first: Any = actualArray[0]
    assertIs<Int>(first)
    // first is smart-cast to Int now
    println("${first + 1}")
    
    assertContentEquals(expectedArray, actualArray)
    assertContains(expectedArray, 2)

    val x = sin(PI)

    // precision parameter
    val tolerance = 0.000001

    assertEquals(0.0, x, tolerance)
}

Mevcut onaylama işlevleriyle ilgili olarak - artık assertTrue(), assertFalse() ve wait() 'e geçirilen lambda içindeki askıya alma işlevlerini çağırmak mümkündür çünkü bu işlevler artık satır içi.


Kotlin'nin yeni versiyonu hakkında daha fazla bilgi almak için referans sayfasını ziyaret edebilirsiniz: https://blog.jetbrains.com/kotlin/2021/04/kotlin-1-5-0-rc-released


#android #kotlin

0 yorum

Son Paylaşımlar

Hepsini Gör