Files.find() with BiPredicate in Kotlin

2019-02-27 14:32发布

问题:

I want to find all files in files tree. In Java I'd write something like:

try(Stream<Path< paths = Files.find(startingPath, maxDepth,
   (path, attributes) -> !attributes.isDirectory())) {
          paths.forEach(System.out::println);
}

But I am using kotlin, and came up with this:

Files.find(startingPath,maxDepth,
        { (path, basicFileAttributes) -> !basicFileAttributes.isDirectory()}
).use { println(it) }

However, this gives me error:

Cannot infer a type for this parameter. Please specify it explicitly.

Type mismatch:

Required: BiPredicate< Path!, BasicFileAttributes! >!

Found: (???) -> Boolean

Any idea how to use BiPredicate in this case?
Thanks in advance

回答1:

BiPredicate is a Java class, Kotlin function types are not directly compatible. This is due to missing SAM conversions, also explained in my recent answer here.

What you need to pass is an object matcher of type BiPredicate<Path, BasicFileAttributes>. To clarify, something like this:

val matcher = object : BiPredicate<Path, BasicFileAttributes>
{
    override fun test(path: Path, basicFileAttributes: BasicFileAttributes): Boolean
    {
        return !basicFileAttributes.isDirectory()
    }
}

This can be simplified to:

val matcher = BiPredicate<Path, BasicFileAttributes> { path, basicFileAttributes ->
    !basicFileAttributes.isDirectory()
}

When you pass it to Files.find(), Kotlin is even able to infer the generic parameter types. So in total, your expression would be:

Files.find(startingPath, maxDepth, BiPredicate { path, basicFileAttributes ->
    !basicFileAttributes.isDirectory()
}).use { println(it) }


回答2:

You had two problems there. Use BiPredicate { x, y -> code } for the type mismatch error the compiler gives you, and then get the actually do what it intends to do by replacing .use with forEach. Otherwise it prints the stream object.

Files.find(startingPath, maxDepth,
        BiPredicate { path, basicFileAttributes -> !basicFileAttributes.isDirectory() }
).forEach { println(it) }