Reputation: 8728
I'm having trouble understanding why
class Main {
private val outputStreams: List<OutputStream>
@JvmOverloads constructor(outputStreams: List<OutputStream> = LinkedList()) {
if(outputStreams.contains(null)) {
throw IllegalArgumentException("outputStreams mustn't contain null")
}
this.outputStreams = outputStreams
}
}
causes the compilation error ...Main.kt:[12,26] Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
.
If I use outputStreams.contains(null as OutputStream))
the compilation succeeds, but Main(LinkedList<OutputStream>())
fails at runtime due to
kotlin.TypeCastException: null cannot be cast to non-null type java.io.OutputStream
at kotlinn.collection.contains.nulll.check.Main.<init>(Main.kt:12)
at kotlinn.collection.contains.nulll.check.MainTest.testInit(MainTest.kt:13)
which leaves me with no other approach for keeping the code as close to the original Java as possible which is my intend as well as understanding this issue as it is rather than searching for a workaround.
Upvotes: 4
Views: 10024
Reputation: 867
filterNotNull() method can filter out all null objects from the collection so you could use the code below. Obviously, you need to inform the compiler that objects in the collection are nullable. I changed the OutputStream type to String for easier testing.
class Main{
private val outputStreams: List<String?>
@JvmOverloads constructor(outputStreams: List<String?> = LinkedList()) {
if(outputStreams.filterNotNull().size < outputStreams.size) {
throw IllegalArgumentException("outputStreams mustn't contain null")
}
this.outputStreams = outputStreams
}
fun getOutputStream(): List<String?>{
return outputStreams
}
}
A second approach would be to use let T.let(block: (T) -> R): R where you would accept the nullable object, but then you would have to check whether there is any "null" string and react accordingly.
class Main{
lateinit var outputStreams: List<String?>
@JvmOverloads constructor(outputStreams: List<String?> = LinkedList()) {
outputStreams.let {
this.outputStreams = outputStreams
}
}
fun getOutputStream(): List<String?>{
return outputStreams
}
}
fun main(args: Array<String>) {
val outputStreamWithNull: List<String?> = listOf("alpha", "beta", null, "omega")
val mainA = Main(outputStreamWithNull)
mainA.getOutputStream().forEach {
println(it)
}
}
If you are "confident" that the object parameter in the constructor should be a collection of non-null objects, then you can remove ? However, the nullable check on the List collection must be done by an object initialising Main class, so you would basically move the responsibility of catching NullPointerException to someone else.
Upvotes: 1
Reputation: 81889
For the compiler, the parameter outputStreams
cannot contain null
as its type is List<OutputStream>
as opposed to List<OutputStream?>
. The type system does not expect null
to be inside this list, thus no need to check it.
On the other hand, IF that parameter actually could contain null
(since it comes from a Java caller) you should mark it as nullable explicitly: List<OutputStream?>
Upvotes: 4
Reputation: 432
I belive that the answer is List<OutputStream?>
. ?
will make your list can contain null
.
Check the doc: enter link description here
Upvotes: 3