Daftar Kotlin hilang "tambah", "hapus", Peta hilang "pasang", dll?

197

Di Jawa kita bisa melakukan hal berikut

public class TempClass {
    List<Integer> myList = null;
    void doSomething() {
        myList = new ArrayList<>();
        myList.add(10);
        myList.remove(10);
    }
}

Tetapi jika kita menulis ulang ke Kotlin secara langsung seperti di bawah ini

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

Saya mendapatkan kesalahan karena tidak menemukan adddan removeberfungsi dari Daftar saya

Saya bekerja di sekitar casting ke ArrayList, tapi itu aneh perlu melemparkannya, sementara di Jawa casting tidak diperlukan. Dan itu mengalahkan tujuan memiliki Daftar kelas abstrak

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        (myList!! as ArrayList).add(10)
        (myList!! as ArrayList).remove(10)
    }
}

Apakah ada cara bagi saya untuk menggunakan Daftar tetapi tidak perlu melemparkannya, seperti apa yang bisa dilakukan di Jawa?

Elye
sumber
1
Hanya komentar mengapa Anda tidak bisa melakukan myList = nulldan kemudian panggilan tambahkan tanpa !!. Anda dapat mengatasinya dengan menggunakan lateinitkata kunci di depan properti Anda seperti lateinit var myList: List<Int>ini : dengan cara ini Anda tidak perlu segera menginisialisasi daftar, tetapi Anda menjamin kepada kompiler bahwa Anda akan menginisialisasinya sebelum menggunakan daftar tersebut pertama kali. Ini adalah solusi yang lebih halus, tetapi ini menempatkan Anda sebagai pengembang.
Darwind

Jawaban:

351

Tidak seperti banyak bahasa, Kotlin membedakan antara koleksi yang bisa berubah dan tidak dapat diubah (daftar, set, peta, dll). Kontrol yang tepat atas kapan koleksi dapat diedit berguna untuk menghilangkan bug, dan untuk merancang API yang baik.

https://kotlinlang.org/docs/reference/collections.html

Anda harus menggunakan MutableListdaftar.

class TempClass {
    var myList: MutableList<Int> = mutableListOf<Int>()
    fun doSomething() {
        // myList = ArrayList<Int>() // initializer is redundant
        myList.add(10)
        myList.remove(10)
    }
}

MutableList<Int> = arrayListOf() juga harus bekerja.

fulvio
sumber
4
Jawaban yang bagus dan ditulis dengan baik. Saya memilih milik Anda sebagai jawaban model meskipun milik saya di bawah ini :)
Elye
6
Anda tidak perlu membuat daftar tersebut menjadi nol jika Anda segera menginisialisasinya. Saya mengedit jawaban Anda.
Kirill Rakhman
37

Menentukan koleksi Daftar di Kotlin dengan cara yang berbeda:

  • Variabel tidak dapat diubah dengan daftar tidak berubah (hanya baca):

    val users: List<User> = listOf( User("Tom", 32), User("John", 64) )


  • Variabel tidak dapat diubah dengan daftar dapat diubah:

    val users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )

    atau tanpa nilai awal - daftar kosong dan tanpa tipe variabel eksplisit:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    • Anda dapat menambahkan item ke daftar:
      • users.add(anohterUser) atau
      • users += anotherUser(di bawah tenda itu users.add(anohterUser))


  • Variabel yang dapat diubah dengan daftar tidak berubah:

    var users: List<User> = listOf( User("Tom", 32), User("John", 64) )

    atau tanpa nilai awal - daftar kosong dan tanpa tipe variabel eksplisit:

    var users = emptyList<User>()
    • CATATAN: Anda dapat menambahkan * item ke dalam daftar:
      • users += anotherUser - * ia membuat ArrayList baru dan menetapkannya untuk users


  • Variabel yang dapat diubah dengan daftar yang dapat diubah:

    var users: MutableList<User> = mutableListOf( User("Tom", 32), User("John", 64) )

    atau tanpa nilai awal - daftar kosong dan tanpa tipe variabel eksplisit:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    • CATATAN: Anda dapat menambahkan item ke daftar:
      • users.add(anohterUser)
      • tetapi tidak menggunakan users += anotherUser

        Kesalahan: Kotlin: Ambiguitas operator tugas:
        kesenangan operator publik Collection.plus (elemen: String): Daftar didefinisikan dalam kotlin.collections
        @InlineHanya inline operator publik yang menyenangkan MutableCollection.plusAssign (elemen: String): Unit didefinisikan dalam kotlin.collections


lihat juga: https://kotlinlang.org/docs/reference/collections.html

Lukas
sumber
9

Setuju dengan semua jawaban di atas untuk menggunakan MutableList tetapi Anda juga dapat menambah / menghapus dari Daftar dan mendapatkan daftar baru seperti di bawah ini.

val newListWithElement = existingList + listOf(element)
val newListMinusElement = existingList - listOf(element)

Atau

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
salep dinesh
sumber
8

Rupanya, Daftar default Kotlin tidak berubah. Untuk memiliki Daftar yang bisa berubah, orang harus menggunakan MutableList seperti di bawah ini

class TempClass {
    var myList: MutableList<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

Diperbarui Meskipun demikian, tidak disarankan untuk menggunakan MutableList kecuali untuk daftar yang benar-benar ingin Anda ubah. Mengacu pada https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 untuk bagaimana koleksi Read-only menyediakan pengkodean yang lebih baik.

Elye
sumber
Anda benar tentang penggunaan MutableList, namun menginisialisasi dengan itu nulltidak akan berhasil. Hanya panggilan yang dinyatakan aman atau tidak nol yang diizinkan pada jenis penerima yang dapat dibatalkan MutableList<Int>.
fulvio
Ini berfungsi pada saya, dan tidak ada kesalahan ditemukan. Saya tidak perlu menginisialisasi kecuali ketika saya membutuhkannyadoSomething
Elye
@ Elye Saya tahu ini adalah jawaban dan pertanyaan lama, tetapi menggunakan lateinitalih-alih membuat daftar nullable adalah cara yang tepat untuk menyelesaikan masalah ini. Tidak ingat apakah lateinitsudah ditambahkan dari awal Kotlin, tapi ini jelas merupakan solusi saat ini untuk menggunakannya :-)
Darwind
5

Di Kotlin Anda harus menggunakan MutableListatau ArrayList.

Mari kita lihat bagaimana metode MutableListkerjanya:

var listNumbers: MutableList<Int> = mutableListOf(10, 15, 20)
// Result: 10, 15, 20

listNumbers.add(1000)
// Result: 10, 15, 20, 1000

listNumbers.add(1, 250)
// Result: 10, 250, 15, 20, 1000

listNumbers.removeAt(0)
// Result: 250, 15, 20, 1000

listNumbers.remove(20)
// Result: 250, 15, 1000

for (i in listNumbers) { 
    println(i) 
}

Mari kita lihat bagaimana metode ArrayListkerjanya:

var arrayNumbers: ArrayList<Int> = arrayListOf(1, 2, 3, 4, 5)
// Result: 1, 2, 3, 4, 5

arrayNumbers.add(20)
// Result: 1, 2, 3, 4, 5, 20

arrayNumbers.remove(1)
// Result: 2, 3, 4, 5, 20

arrayNumbers.clear()
// Result: Empty

for (j in arrayNumbers) { 
    println(j) 
}
Andy Fedoroff
sumber
4

Anda dapat melakukannya dengan membuat yang baru seperti ini.

var list1 = ArrayList<Int>()
var list2  = list1.toMutableList()
list2.add(item)

Sekarang Anda dapat menggunakan list2, Terima kasih.

Dalvinder Singh
sumber
2

Membatasi Mutabilitas terhadap Pembangun

Jawaban teratas di sini dengan benar berbicara tentang perbedaan di Kotlin antara hanya-baca List(CATATAN: ini hanya-baca, bukan "tidak berubah" ), dan MutableList.

Secara umum, seseorang harus berusaha untuk menggunakan daftar read-only, namun, kemampuan berubah-ubah masih sering berguna pada waktu konstruksi , terutama ketika berhadapan dengan perpustakaan pihak ketiga dengan antarmuka non-fungsional. Untuk kasus-kasus di mana teknik konstruksi alternatif tidak tersedia, seperti menggunakan listOfsecara langsung, atau menerapkan konstruksi fungsional seperti foldatau reduce, konstruksi "fungsi pembangun" sederhana seperti berikut ini dengan baik menghasilkan daftar read-only dari yang dapat diubah sementara:

val readonlyList = mutableListOf<...>().apply {
  // manipulate your list here using whatever logic you need
  // the `apply` function sets `this` to the `MutableList`
  add(foo1)
  addAll(foos)
  // etc.
}.toList()

dan ini dapat dengan baik dienkapsulasi menjadi fungsi utilitas inline yang dapat digunakan kembali:

inline fun <T> buildList(block: MutableList<T>.() -> Unit) = 
  mutableListOf<T>().apply(block).toList()

yang bisa disebut seperti ini:

val readonlyList = buildList<String> {
  add("foo")
  add("bar")
}

Sekarang, semua mutabilitas terisolasi ke satu ruang lingkup blok yang digunakan untuk pembangunan daftar read-only, dan sisa kode Anda menggunakan daftar read-only yang merupakan output dari pembangun.

UPDATE : Pada Kotlin 1.3.70, buildListfungsi tepat di atas tersedia di perpustakaan standar sebagai fungsi eksperimental, bersama dengan analog buildSetdan buildMap. Lihat https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Raman
sumber
terima kasih dan bekerja dengan baik dengan logika bisnis dalam metode terapkan, bahkan menggunakan anotherList.ForEach {add (foo)} di dalam .appy {}
BENN1TH
1

Dalam konsep data abadi, mungkin ini cara yang lebih baik:

class TempClass {
    val list: List<Int> by lazy {
        listOf<Int>()
    }
    fun doSomething() {
        list += 10
        list -= 10
    }
}
bbsimon
sumber
1

A listadalah immutabledengan Default, Anda bisa menggunakannya ArrayList. seperti ini :

 val orders = arrayListOf<String>()

maka Anda dapat add/deleteitem dari ini seperti di bawah ini:

orders.add("Item 1")
orders.add("Item 2")

secara default ArrayListadalah mutableagar Anda dapat melakukan operasi di atasnya.

Guntur
sumber