Woes with arrays


#1

I spend the evening with this and now give up. Maybe someone here can help me:

To figure out how Kotlin and Java classes can be used together, I tried to make myself a matrix of the
different kinds of arrays and how they are printed in human readable form and converted to each other:
*  int[] (from Java)

  • Integer[] (from Java)
  • List<Integer> (from Java Collections so identical in Kotlin)
  • Array<Int> (from Kotlin)

I didn’t get very far though. Can anybody help me with some of the FIXME lines?

package de.lathspell.test.kotlin

import java.util.Arrays
import java.util.List
import java.util.ArrayList
import java.util.Collections
import java.util.Collection

import junit.framework.Assert
import junit.framework.TestCase
import org.apache.commons.lang3.ArrayUtils

import de.lathspell.test.kotlin.ArraysTestProvider

class ArrayTest : TestCase(“ArrayTest”) {

  fun testArrays() {
  /** Java primitives arrays - returns Java int[] */
  val ia : IntArray? = ArraysTestProvider.getIntArray();
  Assert.assertTrue(ia.toString().startsWith("[I@")) &nbsp;&nbsp;Assert.assertEquals("[0, 0, 0, 4]", Arrays.toString(ia))

  &nbsp;&nbsp;/** Java object arrays - returns Java Integer[] */
  &nbsp;&nbsp;val iia : Array&lt;Int?&gt;? = ArraysTestProvider.getIntegerArray()
  &nbsp;&nbsp;Assert.assertTrue(iia.toString().startsWith("[Ljava.lang.Integer;@"))
  &nbsp;&nbsp;// FIXME: Assert.assertEquals("[0, 0, 0, 4]", std.util.arrayList(iia))

  &nbsp;&nbsp;/** Java Collections (work the same in Kotlin) */
  &nbsp;&nbsp;val ci : List&lt;Int?&gt;? = ArraysTestProvider.getCollectionArray();
  &nbsp;&nbsp;// FIXME: Assert.assertEquals("[Ljava.lang.Integer;@", typeinfo(ci).toString())
  &nbsp;&nbsp;Assert.assertEquals("[0, 0, 0, 4]", ci.toString())

  &nbsp;&nbsp;/** Kotlin Array&lt;primitive&gt; */
  &nbsp;&nbsp;val kai : Array&lt;Int&gt; = array(0, 0, 0, 0)
  &nbsp;&nbsp;Assert.assertTrue(true)
  &nbsp;&nbsp;kai[kai.size -1] = 4
  &nbsp;&nbsp;Assert.assertTrue(kai.toString().startsWith("[Ljava.lang.Integer;@"))
  &nbsp;&nbsp;Assert.assertEquals("[0, 0, 0, 4]", kai.toList().toString())

  &nbsp;&nbsp;/** Converting */
  &nbsp;&nbsp;// FIXME: val ci_from_ia : List&lt;Int?&gt; = Arrays.asList(ArrayUtils.toObject(ia))
  &nbsp;&nbsp;// FIXME: val ci_from_iia : List&lt;Int?&gt; = Arrays.asList(iia)
  &nbsp;&nbsp;val ci_from_kai : List&lt;Int&gt;? = kai.toList()
  &nbsp;&nbsp;// FIXME: val ia_from_ci : IntArray = ci.toArray(ia as Array&lt;Int&gt;?)
  &nbsp;&nbsp;val ia_from_iia : IntArray = ArrayUtils.toPrimitive(iia) ?: IntArray(0)
  &nbsp;&nbsp;// FIXME: val ia_from_kai : IntArray = kai.toList().
  &nbsp;&nbsp;val kai_from_ia : Array&lt;Int?&gt; = ArrayUtils.toObject(ia) ?: Array&lt;Int&gt;(0)
  &nbsp;&nbsp;val kai_from_iia : Array&lt;Int?&gt; = iia ?: Array&lt;Int&gt;(0)
  &nbsp;&nbsp;// FIXME: val kai_from_ci : Array&lt;Int&gt; = ci.toArray(kai) // compiles in either IDEA or Maven?!

  }


The Java class:

package de.lathspell.test.kotlin;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ArraysTestProvider {

  /** Get a Java primitives array. */
  public static int[] getIntArray() {
  int[] ia = new int[4];
  ia[ia.length - 1] = 4;
  return ia;
  }

  /** Get a Java Object array. */
  public static Integer[] getIntegerArray() {
  Integer[] iia = new Integer[] {0, 0, 0, 0}; // default is { null, null, null, null }
  iia[iia.length - 1] = 4;
  return iia;
  }

  /** Get a Java Collection array. */
  public static List<Integer> getCollectionArray() {
  ArrayList<Integer> ci = new ArrayList<Integer>();
  Collections.addAll(ci, new Integer(0), new Integer(0), new Integer(0), new Integer(0));
  ci.set(ci.size() - 1, 4);
  return ci;
  }

}


#2

Hi,

Sorry for the delayed answer.

First thing to note here is that arrays are only needed in two situations:

  • Some legacy APIs require them
  • You really need the performance benefits arrays bring

Both things are rather rare, so even if arrays are a little inconvenient somewhere, we do not consider this a huge problem. Use collections, they are nice.

To your questions:

  1. Convert an array to a list


    ``
            // FIXME: Assert.assertEquals("[0, 0, 0, 4]", std.util.arrayList(iia))


    When you say arrayList(foo) you get an array list of length 1 whose only element is foo.
    To turn in array to a list, say: iia.toList()

  2. ArrayList remains an ArrayList
    ``

            /** Java Collections (work the same in Kotlin) */
      val ci : List<Int?>? = ArraysTestProvider.getCollectionArray();
      // FIXME: Assert.assertEquals("[Ljava.lang.Integer;@", typeinfo(ci).toString())
      Assert.assertEquals("[0, 0, 0, 4]", ci.toString())

    I don’t see why you expect ci to be of an array type, when getCollectionArray() returns an ArrayList. You get an ArrayList object, and its type info says so.
  3. Conversions
    <pre><code class="lang-kotlin"> &nbsp;&nbsp;// FIXME: val ci_from_ia : List&lt;Int?&gt; = Arrays.asList(ArrayUtils.toObject(ia)) </code></code></pre><div>There should be IntArray.toList() extension function, but apparently it is missing for now. Feel free to file an issue <a href="http://youtrack.jetbrains.com/issues/KT">here</a>.

            // FIXME: val ci_from_iia : List<Int?> = Arrays.asList(iia)
    iia.toList() works fine.
    ``
            // FIXME: val ia_from_ci : IntArray = ci.toArray(ia as Array<Int>?)
    You expect to receive a primitive array from a collection of boxed values. This may be fair, but this is not how things work. Actually, toArray() should return an array of boxed values: Array<Int?> Due to this bug: http://youtrack.jetbrains.com/issue/KT-1558 you can't make it work now, but the bug will be fixed soon. ``
            // FIXME: val ia_from_kai : IntArray = kai.toList().
    Why do you expect a toList() to return an array?
    ``
            // FIXME: val kai_from_ci : Array<Int> = ci.toArray(kai) // compiles in either IDEA or Maven?!
    This fails to compile due to the aferomentioned bug.

    If you have more questions, feel free to ask.


#3

Hello

Thanks to your suggestions, I got finally rid of all the FIXME lines. Still, some conversions look really ugly.

E.g. isn’t there an easier way to convert from List<Int> to List<Int?> or from Array<Int> to Array<Int?> ?
One would think that a simple assignment would work here as any element of the not nullable List<Int>
of course fits into a List<Int?>.

import java.util.Arrays
import java.util.List
import java.util.ArrayList
import java.util.Collections
import java.util.Collection
import kotlin.nullable.filterNotNull

import org.apache.commons.lang3.ArrayUtils
import org.junit.Assert.*
import org.junit.Test
import kotlin.nullable.toList

class ArraysTest {

  [Test]
  fun testArrays() {
  /** Java Collections (work the same in Kotlin) */
  val ciq : List<Int?> = ArrayTestProvider.getCollectionArray().sure()
  assertEquals("[0, 0, 0, 4]", ciq.toString())

  &nbsp;&nbsp;val ci : List&lt;Int&gt; = ArrayTestProvider.getCollectionArray().sure().filterNotNull()
  &nbsp;&nbsp;assertEquals("[0, 0, 0, 4]", ci.toString())
  &nbsp;&nbsp;/** Java primitives arrays - returns Java int[] */
  &nbsp;&nbsp;val ia : IntArray = ArrayTestProvider.getIntArray().sure()
  &nbsp;&nbsp;assertTrue(ia.toString().startsWith("[I@"))
  &nbsp;&nbsp;assertEquals("[0, 0, 0, 4]", Arrays.toString(ia))
  &nbsp;&nbsp;/** Java object arrays - returns Java Integer[] */
  &nbsp;&nbsp;val iia : Array&lt;Int?&gt; = ArrayTestProvider.getIntegerArray().sure()
  &nbsp;&nbsp;assertTrue(iia.toString().startsWith("[Ljava.lang.Integer;@"))
  &nbsp;&nbsp;assertEquals("[0, 0, 0, 4]", iia.toList().toString())

  &nbsp;&nbsp;/** Kotlin Array&lt;primitive&gt; */
  &nbsp;&nbsp;val kai : Array&lt;Int&gt; = array(0, 0, 0, 4)
  &nbsp;&nbsp;assertTrue(kai.toString().startsWith("[Ljava.lang.Integer;@"))
  &nbsp;&nbsp;assertEquals("[0, 0, 0, 4]", kai.toList().toString())

  &nbsp;&nbsp;// Converting
  &nbsp;&nbsp;val ciq_from_ci : List&lt;Int?&gt; = ArrayList&lt;Int?&gt;(); ciq_from_ci.addAll(ci.toList())
  &nbsp;&nbsp;// BUG: val ciq_from_ia : List&lt;Int?&gt; = ia.toList() // KT-1788 suggests IntArray.toList()
  &nbsp;&nbsp;val ciq_from_iia : List&lt;Int?&gt; = iia.toList()
  &nbsp;&nbsp;val ciq_from_kai : List&lt;Int?&gt; = ArrayList&lt;Int?&gt;(); ciq_from_kai.addAll(kai.toList())

  &nbsp;&nbsp;val ci_from_ciq : List&lt;Int&gt; = ciq.filterNotNull()
  &nbsp;&nbsp;// BUG: val ci_from_ia : List&lt;Int&gt; = ia.toList() // KT-1788 suggests IntArray.toList()
  &nbsp;&nbsp;val ci_from_iia : List&lt;Int&gt; = iia.toList().filterNotNull()
  &nbsp;&nbsp;val ci_from_kai : List&lt;Int&gt; = kai.toList()

  &nbsp;&nbsp;// BUG: val ia_from_ciq : IntArray = ArrayUtils.toPrimitive(ciq.toList()).sure() // KT-1790 Compiler Crash
  &nbsp;&nbsp;// BUG: val ia_from_ci : IntArray = ArrayUtils.toPrimitive(ci.toList()).sure() // KT-1790 Compiler Crash
  &nbsp;&nbsp;val ia_from_iia : IntArray = ArrayUtils.toPrimitive(iia).sure()
  &nbsp;&nbsp;val ia_from_kai : IntArray = ArrayUtils.toPrimitive(kai as Array&lt;Int?&gt;).sure()

  &nbsp;&nbsp;// BUG: val iia_from_ciq : Array&lt;Int?&gt; = ciq.toArray(kai)&nbsp;&nbsp;// KT-1558 Exception while analyzing
  &nbsp;&nbsp;// BUG: val iia_from_ci : Array&lt;Int?&gt; = ci.toArray(kai)&nbsp;&nbsp;// KT-1558 Exception while analyzing
  &nbsp;&nbsp;val iia_from_ia : Array&lt;Int?&gt; = ArrayUtils.toObject(ia).sure()
  &nbsp;&nbsp;val iia_from_kai : Array&lt;Int?&gt; = ArrayUtils.toObject(ArrayUtils.toPrimitive(kai as Array&lt;Int?&gt;)).sure()

  &nbsp;&nbsp;// BUG: val kai_from_ci : Array&lt;Int&gt; = ciq.toArray(kai)&nbsp;&nbsp;// KT-1558 Exception while analyzing
  &nbsp;&nbsp;// BUG: val kai_from_ciq : Array&lt;Int&gt; = ciq.toArray(kai)&nbsp;&nbsp;// KT-1558 Exception while analyzing
  &nbsp;&nbsp;val kai_from_ia : Array&lt;Int&gt; = ArrayUtils.toObject(ia).toList().filterNotNull().toArray(kai) // ArrayStoreException
  &nbsp;&nbsp;val kai_from_iia : Array&lt;Int&gt; = iia.toList().filterNotNull().toArray(kai) // ArrayStoreException

  }
}


#4

BTW the various toList() methods are aviable on IntArray,  DoubleArray et al.

I’ve not tried it but you could probably convert to a nullable List via map()

val list: List<Int?> = someArray.map<Int?> { it }