Ek örnekler için Java 8 Stream Tutorial'dan Kotlin'e dönüştürülmüş tüm örnekler . Her örneğin başlığı, kaynak makaleden türetilmiştir:
Akışlar nasıl çalışır?
// Java:
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
// C1
// C2
// Kotlin:
val list = listOf("a1", "a2", "b1", "c2", "c1")
list.filter { it.startsWith('c') }.map (String::toUpperCase).sorted()
.forEach (::println)
Farklı Akış Çeşitleri # 1
// Java:
Arrays.asList("a1", "a2", "a3")
.stream()
.findFirst()
.ifPresent(System.out::println);
// Kotlin:
listOf("a1", "a2", "a3").firstOrNull()?.apply(::println)
veya String'de ifPresent adlı bir uzantı işlevi oluşturun:
// Kotlin:
inline fun String?.ifPresent(thenDo: (String)->Unit) = this?.apply { thenDo(this) }
// now use the new extension function:
listOf("a1", "a2", "a3").firstOrNull().ifPresent(::println)
Ayrıca bakınız: apply()fonksiyon
Ayrıca bkz: Uzantı İşlevleri
Ayrıca bkz: ?.Güvenli Çağrı operatörü ve genel olarak kuralsızlık: Kotlin'de, null değerlerle başa çıkmanın, onları referans göstermenin veya dönüştürmenin deyimsel yolu nedir?
Farklı Akış Türleri # 2
// Java:
Stream.of("a1", "a2", "a3")
.findFirst()
.ifPresent(System.out::println);
// Kotlin:
sequenceOf("a1", "a2", "a3").firstOrNull()?.apply(::println)
Farklı Akımlar # 3
// Java:
IntStream.range(1, 4).forEach(System.out::println);
// Kotlin: (inclusive range)
(1..3).forEach(::println)
Farklı Akış Çeşitleri # 4
// Java:
Arrays.stream(new int[] {1, 2, 3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println); // 5.0
// Kotlin:
arrayOf(1,2,3).map { 2 * it + 1}.average().apply(::println)
Farklı Akış Türleri # 5
// Java:
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.max()
.ifPresent(System.out::println); // 3
// Kotlin:
sequenceOf("a1", "a2", "a3")
.map { it.substring(1) }
.map(String::toInt)
.max().apply(::println)
Farklı Akış Türleri # 6
// Java:
IntStream.range(1, 4)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a3
// Kotlin: (inclusive range)
(1..3).map { "a$it" }.forEach(::println)
Farklı Akış Çeşitleri # 7
// Java:
Stream.of(1.0, 2.0, 3.0)
.mapToInt(Double::intValue)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a3
// Kotlin:
sequenceOf(1.0, 2.0, 3.0).map(Double::toInt).map { "a$it" }.forEach(::println)
Sipariş Neden Önemlidir?
Java 8 Stream Eğitimi'nin bu bölümü Kotlin ve Java için aynıdır.
Akışları Yeniden Kullanma
Kotlin'de, koleksiyonun türüne birden fazla kez tüketilip tüketilemeyeceğine bağlıdır. A Sequence, her seferinde yeni bir yineleyici oluşturur ve "yalnızca bir kez kullan" seçeneğini belirtmedikçe, her işlem yapıldığında başlangıç durumuna sıfırlanabilir. Bu nedenle Java 8 akışında aşağıdakiler başarısız olur, ancak Kotlin'de çalışır:
// Java:
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("b"));
stream.anyMatch(s -> true); // ok
stream.noneMatch(s -> true); // exception
// Kotlin:
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
stream.forEach(::println) // b1, b2
println("Any B ${stream.any { it.startsWith('b') }}") // Any B true
println("Any C ${stream.any { it.startsWith('c') }}") // Any C false
stream.forEach(::println) // b1, b2
Ve Java'da aynı davranışı elde etmek için:
// Java:
Supplier<Stream<String>> streamSupplier =
() -> Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
streamSupplier.get().anyMatch(s -> true); // ok
streamSupplier.get().noneMatch(s -> true); // ok
Bu nedenle Kotlin'de verilerin sağlayıcısı sıfırlanıp yeni bir yineleyici sağlayıp sağlayamayacağına karar verir. Ancak kasıtlı Sequenceolarak bir kerelik yinelemeyi kısıtlamak istiyorsanız, constrainOnce()işlevi Sequenceaşağıdaki gibi kullanabilirsiniz :
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
.constrainOnce()
stream.forEach(::println) // b1, b2
stream.forEach(::println) // Error:java.lang.IllegalStateException: This sequence can be consumed only once.
Gelişmiş İşlemler
Örnek 5'i toplayın (evet, diğer cevapta bulunanları atladım)
// Java:
String phrase = persons
.stream()
.filter(p -> p.age >= 18)
.map(p -> p.name)
.collect(Collectors.joining(" and ", "In Germany ", " are of legal age."));
System.out.println(phrase);
// In Germany Max and Peter and Pamela are of legal age.
// Kotlin:
val phrase = persons.filter { it.age >= 18 }.map { it.name }
.joinToString(" and ", "In Germany ", " are of legal age.")
println(phrase)
// In Germany Max and Peter and Pamela are of legal age.
Bir yan not olarak, Kotlin'de basit veri sınıfları oluşturabilir ve test verilerini aşağıdaki gibi başlatabiliriz:
// Kotlin:
// data class has equals, hashcode, toString, and copy methods automagically
data class Person(val name: String, val age: Int)
val persons = listOf(Person("Tod", 5), Person("Max", 33),
Person("Frank", 13), Person("Peter", 80),
Person("Pamela", 18))
Örnek 6'yı toplayın
// Java:
Map<Integer, String> map = persons
.stream()
.collect(Collectors.toMap(
p -> p.age,
p -> p.name,
(name1, name2) -> name1 + ";" + name2));
System.out.println(map);
// {18=Max, 23=Peter;Pamela, 12=David}
Tamam, Kotlin için daha ilgi çekici bir dava. İlk olarak, Mapbir koleksiyondan / diziden oluşturmanın varyasyonlarını keşfetmek için yanlış yanıtlar :
// Kotlin:
val map1 = persons.map { it.age to it.name }.toMap()
println(map1)
// output: {18=Max, 23=Pamela, 12=David}
// Result: duplicates overridden, no exception similar to Java 8
val map2 = persons.toMap({ it.age }, { it.name })
println(map2)
// output: {18=Max, 23=Pamela, 12=David}
// Result: same as above, more verbose, duplicates overridden
val map3 = persons.toMapBy { it.age }
println(map3)
// output: {18=Person(name=Max, age=18), 23=Person(name=Pamela, age=23), 12=Person(name=David, age=12)}
// Result: duplicates overridden again
val map4 = persons.groupBy { it.age }
println(map4)
// output: {18=[Person(name=Max, age=18)], 23=[Person(name=Peter, age=23), Person(name=Pamela, age=23)], 12=[Person(name=David, age=12)]}
// Result: closer, but now have a Map<Int, List<Person>> instead of Map<Int, String>
val map5 = persons.groupBy { it.age }.mapValues { it.value.map { it.name } }
println(map5)
// output: {18=[Max], 23=[Peter, Pamela], 12=[David]}
// Result: closer, but now have a Map<Int, List<String>> instead of Map<Int, String>
Ve şimdi doğru cevap için:
// Kotlin:
val map6 = persons.groupBy { it.age }.mapValues { it.value.joinToString(";") { it.name } }
println(map6)
// output: {18=Max, 23=Peter;Pamela, 12=David}
// Result: YAY!!
Listeleri daraltmak ve örnekten 'e jointToStringtaşınması için bir transformatör sağlamak için eşleşen değerlere katılmamız gerekiyordu .PersonPerson.name
Örnek 7'yi toplayın
Tamam, bu bir gelenek olmadan kolayca yapılabilir Collector, bu yüzden onu Kotlin yolunu çözelim, sonra Kotlin'de Collector.summarizingIntyerel olarak mevcut olmayan benzer bir sürecin nasıl yapılacağını gösteren yeni bir örnek alalım .
// Java:
Collector<Person, StringJoiner, String> personNameCollector =
Collector.of(
() -> new StringJoiner(" | "), // supplier
(j, p) -> j.add(p.name.toUpperCase()), // accumulator
(j1, j2) -> j1.merge(j2), // combiner
StringJoiner::toString); // finisher
String names = persons
.stream()
.collect(personNameCollector);
System.out.println(names); // MAX | PETER | PAMELA | DAVID
// Kotlin:
val names = persons.map { it.name.toUpperCase() }.joinToString(" | ")
Bu önemsiz bir örnek aldı benim hatam değil !!! Tamam, burada summarizingIntKotlin için yeni bir yöntem ve eşleşen bir örnek:
Özetleme Örneği
// Java:
IntSummaryStatistics ageSummary =
persons.stream()
.collect(Collectors.summarizingInt(p -> p.age));
System.out.println(ageSummary);
// IntSummaryStatistics{count=4, sum=76, min=12, average=19.000000, max=23}
// Kotlin:
// something to hold the stats...
data class SummaryStatisticsInt(var count: Int = 0,
var sum: Int = 0,
var min: Int = Int.MAX_VALUE,
var max: Int = Int.MIN_VALUE,
var avg: Double = 0.0) {
fun accumulate(newInt: Int): SummaryStatisticsInt {
count++
sum += newInt
min = min.coerceAtMost(newInt)
max = max.coerceAtLeast(newInt)
avg = sum.toDouble() / count
return this
}
}
// Now manually doing a fold, since Stream.collect is really just a fold
val stats = persons.fold(SummaryStatisticsInt()) { stats, person -> stats.accumulate(person.age) }
println(stats)
// output: SummaryStatisticsInt(count=4, sum=76, min=12, max=23, avg=19.0)
Ancak bir uzantı işlevi oluşturmak daha iyidir, 2 aslında Kotlin stdlib'deki stilleri eşleştirmek için:
// Kotlin:
inline fun Collection<Int>.summarizingInt(): SummaryStatisticsInt
= this.fold(SummaryStatisticsInt()) { stats, num -> stats.accumulate(num) }
inline fun <T: Any> Collection<T>.summarizingInt(transform: (T)->Int): SummaryStatisticsInt =
this.fold(SummaryStatisticsInt()) { stats, item -> stats.accumulate(transform(item)) }
Artık yeni summarizingIntişlevleri kullanmanın iki yolu var :
val stats2 = persons.map { it.age }.summarizingInt()
// or
val stats3 = persons.summarizingInt { it.age }
Ve bunların hepsi aynı sonuçları veriyor. Bu eklentiyi, Sequenceuygun ilkel türler üzerinde ve bunlarda çalışmak için de oluşturabiliriz .
Eğlenmek için Java JDK kodunu ve bu özetin uygulanması için gereken Kotlin özel kodunu karşılaştırın .
collect(Collectors.toList())ya da benzer bir şey dışında bir seçeneğiniz olmadığı durumlarda , bu sorunla karşılaşabilirsiniz: stackoverflow.com/a/35722167/3679676 (geçici çözümlerle ilgili sorun)