Lista de Kotlin faltando "adicionar", "remover", mapa ausente "colocar", etc?

197

Em Java, poderíamos fazer o seguinte

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

Mas se reescrevê-lo para Kotlin diretamente como abaixo

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

Eu recebi o erro de não encontrar adde removefuncionar da minha lista

Eu trabalho em torno da transmissão para ArrayList, mas é estranho precisar lançá-lo, enquanto no Java a transmissão não é necessária. E isso derrota o propósito de ter a classe abstrata List

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

Existe uma maneira de eu usar a lista, mas não precisar transmiti-la, como o que poderia ser feito em Java?

Elye
fonte
1
Apenas um comentário do motivo pelo qual você não pode fazer myList = nulle, posteriormente, adicionar sem chamar !!. Você pode superar isso usando a lateinitpalavra - chave na frente de sua propriedade da seguinte maneira: lateinit var myList: List<Int>dessa forma, não será necessário inicializar a lista imediatamente, mas garante ao compilador que a inicializará antes de usar a lista pela primeira vez. É uma solução mais suave, mas coloca uma responsabilidade em você como desenvolvedor.
Darwind 21/08/19

Respostas:

351

Ao contrário de muitos idiomas, o Kotlin faz distinção entre coleções mutáveis ​​e imutáveis ​​(listas, conjuntos, mapas, etc.). O controle preciso sobre exatamente quando as coleções podem ser editadas é útil para eliminar bugs e criar boas APIs.

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

Você precisará usar uma MutableListlista.

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() também deve funcionar.

fulvio
fonte
4
Resposta agradável e bem escrita. Eu estou escolhendo o seu como o modelo de resposta, apesar de ter o meu abaixo :)
Elye
6
Você não precisa tornar a lista anulável se a inicializar imediatamente. Eu editei sua resposta.
Kirill Rakhman
37

Definindo uma coleção de listas no Kotlin de diferentes maneiras:

  • Variável imutável com lista imutável (somente leitura):

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


  • Variável imutável com lista mutável:

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

    ou sem valor inicial - lista vazia e sem tipo explícito de variável:

    val users = mutableListOf<User>()
    //or
    val users = ArrayList<User>()
    • você pode adicionar itens à lista:
      • users.add(anohterUser) ou
      • users += anotherUser(sob o capô é users.add(anohterUser))


  • Variável mutável com lista imutável:

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

    ou sem valor inicial - lista vazia e sem tipo explícito de variável:

    var users = emptyList<User>()
    • NOTA: você pode adicionar * itens à lista:
      • users += anotherUser - * cria novo ArrayList e o atribui a users


  • Variável mutável com lista mutável:

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

    ou sem valor inicial - lista vazia e sem tipo explícito de variável:

    var users = emptyList<User>().toMutableList()
    //or
    var users = ArrayList<User>()
    • NOTA: você pode adicionar itens à lista:
      • users.add(anohterUser)
      • mas não usando users += anotherUser

        Erro: Kotlin: Ambiguidade dos operadores de atribuição: operador
        público divertido Collection.plus (elemento: String): Lista definida em kotlin.collections
        @InlineOnly operador público interno divertido MutableCollection.plusAssign (elemento: String): unidade definida em kotlin.collections


veja também: https://kotlinlang.org/docs/reference/collections.html

Lukas
fonte
9

Concorde com todas as respostas acima sobre o uso do MutableList, mas você também pode adicionar / remover da Lista e obter uma nova lista, como abaixo.

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

Ou

val newListWithElement = existingList.plus(element)
val newListMinusElement = existingList.minus(element)
salgadinho
fonte
8

Aparentemente, a Lista padrão de Kotlin é imutável. Para ter uma lista que pode mudar, use MutableList como abaixo

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

Atualizado no entanto, não é recomendável usar o MutableList, a menos que para uma lista que você realmente deseja alterar. Refere-se a https://hackernoon.com/read-only-collection-in-kotlin-leads-to-better-coding-40cdfa4c6359 de como somente leitura coleção fornece melhor codificação.

Elye
fonte
Você está correto sobre o uso MutableList, no entanto, inicializá-lo com nullnão funcionará. Somente chamadas declaradas seguras ou não nulas são permitidas em um receptor anulável do tipo MutableList<Int>.
Fulvio
Funciona do meu lado, e nenhum erro foi encontrado. Eu não preciso para inicializar a menos quando eu precisar dele quandodoSomething
Elye
@Elye Eu sei que essa é uma resposta e uma pergunta antigas, mas usar em lateinitvez de tornar a lista anulável é a maneira correta de resolver esse problema. Não me lembro se lateinitfoi adicionado desde o início da Kotlin embora, mas esta é definitivamente a solução hoje em dia para usá-lo :-)
Darwind
5

No Kotlin você tem que usar MutableListou ArrayList.

Vamos ver como os métodos de MutableListtrabalho:

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) 
}

Vamos ver como os métodos de ArrayListtrabalho:

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
fonte
4

Você pode criar um novo como este.

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

Agora você pode usar a lista2, obrigado.

Dalvinder Singh
fonte
2

Confinando a mutabilidade aos construtores

As respostas principais aqui falam corretamente da diferença no Kotlin entre somente leitura List(NOTA: é somente leitura, não "imutável" ) e MutableList.

Em geral, deve-se esforçar-se para usar listas somente leitura, no entanto, a mutabilidade ainda é frequentemente útil no momento da construção , especialmente quando se lida com bibliotecas de terceiros com interfaces não funcionais. Nos casos em que as técnicas alternativas de construção não estão disponíveis, como o uso listOfdireto ou a aplicação de uma construção funcional como foldou reduce, uma construção simples de "função construtora" como a seguinte produz uma lista somente leitura de uma lista temporária mutável:

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()

e isso pode ser bem encapsulado em uma função de utilitário em linha reutilizável:

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

que pode ser chamado assim:

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

Agora, toda a mutabilidade é isolada em um escopo de bloco usado para a construção da lista somente leitura, e o restante do seu código usa a lista somente leitura que é gerada pelo construtor.

ATUALIZAÇÃO : A partir do Kotlin 1.3.70, a buildListfunção exata acima está disponível na biblioteca padrão como uma função experimental, junto com seus análogos buildSete buildMap. Consulte https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/ .

Raman
fonte
graças e trabalhou bem com lógica de negócios dentro do método de aplicar, mesmo usado anotherList.ForEach {add (foo)} dentro do .appy {}
BENN1TH
1

No conceito de dados imutáveis, talvez seja esse o melhor caminho:

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

A listestá immutablepronto Default, você pode usar ArrayList. como isso :

 val orders = arrayListOf<String>()

então você pode add/deleteitens como abaixo:

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

por padrão ArrayListé mutablepara que você possa executar as operações nele.

Trovão
fonte