How does one translate Foo::new from Java to Kotlin?


#1

Java 8 introduced the :: method reference syntax and it's possible to use it with "new" when creating new instances. For example you can create new instances by passing something like Foo::new to a Java 8 stream.

This example concatonates two string arrays in Java using this syntax:

String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
                      .toArray(String[]::new);

It’s generating a new Array. I know there a ways to concatonate arrays in Kotlin, that isn’t my question, my question is with regard to the String[]::new syntax. How is this achievable in Kotlin? If I wanted a Java 8 Stream to generate new instances how do I pass something it will recognize, as in the example I pasted above?


#2

Hi Björn!

This worked for me:

import java.util.stream.Stream

fun main(args: Array<String>) {
  val array = Stream
  .of(“foo”, “bar”, “baz”)
  .toArray { size -> arrayOfNulls<String>(size) }

  println(array.toList()) // [foo, bar, baz]
  println(array.javaClass) // class [Ljava.lang.String;
}


I think this is the simplest way. kotlin.Array internally uses arrayOfNulls().


#3

Thank you for your answer Benjamin. So given this works I suspect the way to substitute method references for `new` is to create a factory function? Like in the case one isn't working with arrays which come with built in functions like arrayOfNulls. If I had a custom class called Foo and I wanted to pass it into a stream map or some other thing that would expect Foo:new in Java 8, I'd have to create a factory function for it in Kotlin.


#4

Somehow, yes.

The Stream interface in Java provides two suitable methods to convert the Stream to an array.

public interface Stream<T> {   Object[] toArray();   <A> A[] toArray(IntFunction<A[]> generator); }

The first method returns `Object[]`, which means we lose our explicit type. The second method accepts an `IntFunction`. The documentation string of this method states:

>The generator function takes an integer, which is the size of the desired array, and produces an array of the desired size.  This can be concisely expressed with an array constructor reference

I guess the array constructor reference String[]::new does nothing else than what { size -&gt; arrayOfNulls&lt;String&gt;(size) } does. I don’t know if this could also be expressed in Kotlin with something like a method or constructor reference.

Update: The docs have a section about constructor references [1]. Unfortunately .toArray(::Array) and .toArray(::Array&lt;String&gt;) and also .toArray(::arrayOfNulls) didn’t work for me.

[1] http://kotlinlang.org/docs/reference/reflection.html#constructor-references


#5

Oh I missed that bit about constructor references. I will read through this. Thank you!


#6

 

public fun <T> ArrayList<T>.addAllYourself(ts: Array<T>) : ArrayList<T> {
  this.addAll(ts)
  return this
}

fun main(args: Array<String>)
{
  val first = arrayOf(“a”, “b”)
  val second = arrayOf(“c”, “d”)

  val both = ArrayList<String>().addAllYourself(first).addAllYourself(second)
  both.forEach
{ println(it) }
}

prints:

a
b
c
d

The absence of extension methods in Java results more and more in programming with static methods the more features are added to the language. This piece of code really isn’t what OO is about:

String[] first = { “a”,“b”};
String[] second = {“c”,“d”};

String[] both = Stream.concat(Arrays.stream(first), Arrays.stream(second)).toArray(String[]::new);

for (String s : both) {
  System.out.println(s);
}