2

Why does this piece of Java code not compile in Kotlin without the explicit type parameter in Collectors.toList<String>()? Is there a more idiomatic way to do this?

// works
List<String> folders = Files.walk(Paths.get(args[0]))
            .filter(it -> it.toFile().isDirectory())
            .map(it -> it.toAbsolutePath().toString())
            .collect(Collectors.toList());

// does not compile - resulting type is `MutableList<in String!>..List<Any?>?` which is not compatible to `List<String>`
val folders: List<String> = Files.walk(Paths.get(args[0]))
            .filter { it.toFile().isDirectory }
            .map { it.toAbsolutePath().toString() }
            .collect(Collectors.toList())

// compiles
val folders: List<String> = Files.walk(Paths.get(args[0]))
            .filter { it.toFile().isDirectory }
            .map { it.toAbsolutePath().toString() }
            .collect(Collectors.toList<String>())
atamanroman
  • 11,607
  • 7
  • 57
  • 81

2 Answers2

3

Why does this piece of Java code not compile in Kotlin without the explicit type parameter in Collectors.toList<String>()?

This looks like a compiler bug to me. I recommend creating an issue in Kotlin (KT) | YouTrack.

Is there a more idiomatic way to do this?

Yes. As Kirill Rakhman comments, "Kotlin has its own File.walk extension method." e.g.:

val folders: List<String> = File(args[0]).walk()
        .filter(File::isDirectory)
        .map(File::getAbsolutePath)
        .toList()

If you prefer using Java 8 streams then checkout Kotlin/kotlinx.support: Extension and top-level functions to use JDK7/JDK8 features in Kotlin 1.0. It defines a Stream<T>.toList() function:

val folders: List<String> = Files.walk(Paths.get(args[0]))
        .filter { it.toFile().isDirectory }
        .map { it.toAbsolutePath().toString() }
        .toList()
Community
  • 1
  • 1
mfulton26
  • 29,956
  • 6
  • 64
  • 88
  • 1
    I'd like to add that `Stream.toList()` is already in the standard library of coming Kotlin 1.1 https://github.com/JetBrains/kotlin/blob/1.1-M1/libraries/stdlib/jre8/src/kotlin/streams/Streams.kt#L35 – Ilya Aug 22 '16 at 15:49
  • Hi, when i'm using the File(path).walk() method, the list contains only the name of the Directory from path, but not the files inside this directory. Any idea ? – SWAppDev Jun 05 '17 at 21:01
0

I've found two ways to make it work without explicitly specifying generic type in both places.

Either you can specify full type of variable with generic covariance

val folders: MutableList<in String> = Files.walk(Paths.get(args[0]))
        .filter { it.toFile().isDirectory }
        .map { it.toAbsolutePath().toString() }
        .collect(Collectors.toList())

or you can simply let Kotlin do its type inference for variable (not generic parameter of method)

val folders2 = Files.walk(Paths.get(args[0]))
        .filter { it.toFile().isDirectory }
        .map { it.toAbsolutePath().toString() }
        .collect(Collectors.toList<String>())
rafal
  • 3,120
  • 1
  • 17
  • 12
  • `MutableList` is rarely a result one expects to get from `collect`. Second workaround is ok. – Ilya Aug 22 '16 at 15:45