una recorrer rangos mutablelist lista example crear colecciones ciclos arreglos kotlin

recorrer - rangos kotlin



Cómo convertir una colección mutable en una inmutable (4)

Actualmente, en Kotlin stdlib no hay implementaciones de List<T> ( Map<K,V> ) que no implementaría también MutableList<T> ( MutableMap<K,V> ). Sin embargo, debido a la característica de delegación de Kotlin, las implementaciones se convierten en una sola línea:

class ImmutableList<T>(private val inner:List<T>) : List<T> by inner class ImmutableMap<K, V>(private val inner: Map<K, V>) : Map<K, V> by inner

También puede mejorar la creación de las contrapartes inmutables con métodos de extensión:

fun <K, V> Map<K, V>.toImmutableMap(): Map<K, V> { if (this is ImmutableMap<K, V>) { return this } else { return ImmutableMap(this) } } fun <T> List<T>.toImmutableList(): List<T> { if (this is ImmutableList<T>) { return this } else { return ImmutableList(this) } }

Lo anterior evita que una persona que llama modifique la List ( Map ) lanzando a una clase diferente. Sin embargo, todavía hay razones para crear una copia del contenedor original para evitar problemas sutiles como ConcurrentModificationException :

class ImmutableList<T> private constructor(private val inner: List<T>) : List<T> by inner { companion object { fun <T> create(inner: List<T>) = if (inner is ImmutableList<T>) { inner } else { ImmutableList(inner.toList()) } } } class ImmutableMap<K, V> private constructor(private val inner: Map<K, V>) : Map<K, V> by inner { companion object { fun <K, V> create(inner: Map<K, V>) = if (inner is ImmutableMap<K, V>) { inner } else { ImmutableMap(hashMapOf(*inner.toList().toTypedArray())) } } } fun <K, V> Map<K, V>.toImmutableMap(): Map<K, V> = ImmutableMap.create(this) fun <T> List<T>.toImmutableList(): List<T> = ImmutableList.create(this)

Si bien lo anterior no es difícil de implementar, ya existen implementaciones de listas y mapas inmutables tanto en Guava como en Eclipse-Collections .

Estaba escribiendo un pequeño fragmento de código en el que manipulo internamente mis datos en un mapa mutable, que a su vez tiene listas mutables.

Quería exponer mis datos al usuario de la API, pero para evitar cualquier publicación insegura de mis datos, quería exponerlos en colecciones inmutables, incluso cuando los datos mutables los manejan internamente.

class School { val roster: MutableMap<Int, MutableList<String>> = mutableMapOf<Int, MutableList<String>>() fun add(name: String, grade: Int): Unit { val students = roster.getOrPut(grade) { mutableListOf() } if (!students.contains(name)) { students.add(name) } } fun sort(): Map<Int, List<String>> { return db().mapValues { entry -> entry.value.sorted() } .toSortedMap() } fun grade(grade: Int) = db().getOrElse(grade, { listOf() }) fun db(): Map<Int, List<String>> = roster //Uh oh! }

Logré exponer solo el Map y la List (que son inmutables) en la API pública de mi clase, pero las instancias a las que estoy exponiendo todavía son intrínsecamente mutables.

Lo que significa que un usuario de la API podría simplemente lanzar mi mapa devuelto como ImmutableMap y obtener acceso a los preciosos datos privados internos de mi clase, que estaban diseñados para estar protegidos de este tipo de acceso.

No pude encontrar un constructor de copias en los métodos mutableMapOf() o mutableListOf() por lo que me preguntaba cuál es la mejor y más eficiente forma de convertir una colección mutable en una inmutable.

¿Algún consejo o recomendación?


Como se mencionó here y here , tendría que escribir su propia implementación de la List para eso, o usar una existente (Me viene a la mente el ImmutableList de Guava, o las Eclipse-Collections como sugirió Andrew ).

Kotlin impone la mutabilidad de la lista (im) solo por la interfaz. No hay implementaciones de MutableList tampoco implementen MutableList .

Incluso el listOf(1,2,3) idiomático listOf(1,2,3) termina llamando a ArraysUtilJVM.asList() de Kotlin, que llama a Arrays.asList() de Java Arrays.asList() que devuelve una lista de ArrayList Java sencilla y antigua.

Si le interesa más proteger su propia lista interna, que sobre la inmutabilidad en sí misma, puede, por supuesto, copiar la colección completa y devolverla como una List , al igual que Kotlin:

return ArrayList(original)


Sé que esta es una pregunta específica de Kotlin y @Malt es correcta, pero me gustaría agregar una alternativa. En particular, considero que Eclipse-Collections , formalmente GS-Collections, es una mejor alternativa a la guayaba para la mayoría de los casos y complementa bien las colecciones integradas de Kotlin.


Una solución clásica es copiar sus datos, de modo que incluso si se modifican, el cambio no afectaría la propiedad de la clase privada:

class School { private val roster = mutableMapOf<Int, MutableList<String>>() fun db(): Map<Int, List<String>> = roster.mapValuestTo {it.value.toList} }