I'm trying to create two almost-same methods that handle nullable and non-nullable arguments slightly differently:
fun parse(type: Any) : MyObject {
return handleParse(type)
}
fun parse(type: Any?) : MyObject? {
if (type == null)
return null
return handleParse(type)
}
But I get this error in Android Studio:
Platform declaration clash: The following declarations have the same JVM signature
The goal is that it automatically handles nullable and non-nullable values in Kotlin, without me using !! every time I call it on nullable terms.
I've already tried adding the #JvmName("-name") annotation as mentioned in this answer but that doesn't work either. Obviously, I can change the method name to something else as well, but that is just circling around and avoiding the issue altogether.
Hoping there's an easy way to do this or at least a sensible workaround. Would also appreciate the reasoning behind the way things currently work, and why I should or shouldn't do this.
Reason why this doesn't work is simple, Java doesn't have null-safe types, meaning that both methods look completely same to Java, and Kotlin aims to provide as much interoperability with Java as possible.
But if you think a bit more about that there is simply no reason for such feature, as you can see your 2nd method already handles everything properly, with addition of 1 if case, which even if this feature exist would have to exist because compiler would need to know whether value in null or not in other to know which method to call anyway.
Common approach that I have seen so far is adding NotNull suffix to your method, for example in your case it would be parseNotNull in case where you don't allow nullable types, this way even when calling code from Java it is clear that parameter shouldn't be null.
Related
As I learn new components in Kotlin, I came accross requireNotNull and checkNotNull but the only difference I've found is that requireNotNull can throw an IllegalArgumentException while checkNotNull can throw an IllegalStateException. Is this the only reason why there are two methods, or I'm missing some under-the-hood implementation detail?
The exception types are the only practical difference, as far as the compiler is concerned — but there's a big difference in intent, for anyone reading the code:
• require…() functions are for checking parameters, to confirm that a function's input fulfils its contract. So you'd normally call them first thing in a function. (Of course, Kotlin's non-nullable types mean that you wouldn't need to call requireNotNull() for a single parameter; but you might need to check a more complex condition on a combination of parameters or their sub-objects.) That's why they throw IllegalArgumentException: it's checking that the arguments are legal.
• check…() functions are for checking the relevant properties, to confirm that the object or whatever is in a valid state for this function to be called now. (Again, any properties that were never null would be typed accordingly, so checkNotNull() is more appropriate for cases where a property, combination, and/or sub-property can be null, but this function mustn't be called when they are.) So they throw IllegalStateException: they're checking that the object's current state allows the function to be called.
In both cases, you could of course write a standard if check (as you would in Java). Or you could use the Elvis operator ?: to do the check the first time the possibly-null value is used. But these functions give you an alternative that's in a more declarative form: you'd normally put them at the top of the function, where they spell out what the function's contract is, in a way that's obvious to anyone glancing at the code.
As a linked answer points out, there are also assert…() functions, which again have more of a semantic difference than a practical one. Those are for detecting programming errors away from the boundary of a function call: for confirming invariants and other conditions, and for all the checks in unit tests and other automated tests.
(Assertions have another important difference: they can be enabled and disabled from the command-line. Though in my experience, that's not a very good thing. If a check is important, it should always be run: be mandatory; if not, then it should be removed, or at least moved to automated tests, once the code is debugged.)
It is a semantic difference and hence it throws different exceptions. RequireNotNull is used to check input values, typically at the beginning of a method, while checkNotNull is used anywhere to check the current state.
If you're looking for differences in implementation, the best place to go would be the source code. In this case it seems like there are no differences aside from the different exception thrown, the source for both methods is otherwise identical.
checkNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalStateException(message.toString())
} else {
return value
}
requireNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
} else {
return value
}
Therefore the difference is purely semantic. The answer from #gidds details some good scenarios for using them both.
class Example(private val childrenByParent: HashMap<String, List<String>>) {
private val parents: List<String> = childrenByParent.keys.toList()
fun getChildrenCount(parentPosition: Int): Int {
return childrenByParent[parents[parentPosition]].size
// error, recommends using "?." or "!!"
}
}
The compiler won't let me call size directly but I don't understand why. There are no nullable types in sight.
If I let the compiler infer the type by doing this:
val infer = childrenByParent[parents[parentPosition]]
I can see that it assumes it's a List<String>?
It seems that I'm quite confused about nullability still. Would appreciate some help. I have a feeling I'm doing something incredibly dumb, but after some searching and testing I failed at fixing this.
I would like for this function to not use ?. or even worse, !!. Is it possible? At least, using HashMap and List<String>.
HashMap.get(Object) returns null when there is no element matching the key you provided, so its return type is effectively nullable, regardless of whether the values are or not.
So unfortunately you have to account for the case in which the key doesn't exist, so your choices are either implementing a case where it doesn't, or just declaring it as non-null with !! if you are sure the key exists.
Otherwise you can use HashMap.containsKey(String) to ensure the key exists and then you can be confident that using !! on the value won't result in a NullPointerException.
However as #gidds pointed out, this is not naturally thread-safe without some more work, so it might be best to just handle the case of the key not being in the map. Also I cannot actually think of many cases where you could be sure that key exists, in which a Map is the most appropriate data structure to use.
Also, even though this is not the case here, remember that nullability is just a feature of Kotlin, so when using some classes originally written in Java, whether an element is nullable or not is unknown. The IDE will usually represent this as Type! where the single ! tells you it is a platform type.
There are some ways to fulfill a null-checking in Kotlin:
1.
if(myVar != null) {
foo(myVar)
}
2.
myVar?.let {
foo(it)
}
3.
myVar?.run {
foo(this)
}
What are the difference between these ways?
Are there any reasons (performance, best practice, code style etc.) why I should prefer on way over the other?
!! is to tell the compiler that I am sure the value of the variable is not null, and if it is null throw a null pointer exception (NPE) where as ?. is to tell the compiler that I am not sure if the value of the variable is null or not, if it is null do not throw any null pointer.
Another way of using a nullable property is safe call operator ?.
This calls the method if the property is not null or returns null if that property is null without throwing an NPE (null pointer exception).
nullableVariable?.someMethodCall()
All three code are behave same null check in operation-wise.
?. is used for chain operations.
bob?.department?.head?.name // if any of the properties in it is null it returns null
To perform a chain operation only for non-null values, you can use the safe call operator together with let
myVar?.let {
foo(it)
}
the above code is good for code style and performance
more details refer Null Safety
The ways 2 and 3 are more idiomatic for Kotlin. Both functions are quite similar. There is little difference with argument passing.
For example, we have a nullable variable:
var canBeNull: String? = null
When you working with T.run you work with extension function calling and you pass this in the closure.
canBeNull?.run {
println(length) // `this` could be omitted
}
When you call T.let you can use it like lambda argument it.
canBeNull?.let {
myString -> println(myString.length) // You could convert `it` to some other name
}
A good article about Kotlin standard functions.
All three are roughly equivalent.
The if case is more like most other languages, and so many developers may find it easier to read.
However, one difference is that the if case will read the value of myVar twice: once for the check, and again when passing it to foo(). That makes a difference, because if myVar is a property (i.e. something that could potentially be changed by another thread), then the compiler will warn that it could have been set to null after the check. If that's a problem (e.g. because foo() expects a non-null parameter), then you'll need to use one of the other cases.
For that reason, the let case has become fairly common practice in Kotlin. (The run case does just about the same thing, but for some reason isn't as popular for this sort of thing. I don't know why.)
Another way around it is to assign myVar to a temporary value, test that, and then use that. That's also more like other languages, but it's more verbose; many people prefer the conciseness of the let case — especially when myVar is actually a complicated expression.
The examples in your question don't show the true reason to decide.
First of all, since you're not using the return value of foo, you should use neither let nor run. Your choice is between also and apply.
Second, since you already have the result you want to null-check in a variable, the difference fades. This is a better motivating example:
complexCall(calculateArg1(), calculateArg2())?.also {
results.add(it)
}
as opposed to
val result = complexCall(calculateArg1(), calculateArg2())
if (result != null) {
results.add(result)
}
The second example declares an identifier, result, which is now available to the rest of the lexical scope, even though you're done with it in just one line.
The first example, on the other hand, keeps everything self-contained and when you go on reading the rest of the code, you are 100% confident that you don't have to keep in mind the meaning of result.
Kotlin have new features with NullPoint-Exception as Compare to Java.
Basically When we do Coding in Java , then we have to Check with !! in every Flied.
But in Kotlin, it is Easy way to Implement First
as Like,
Suppose, in Kotlin
var response:Json?=Null
response:Json?.let {
this part will handle automatic if response is Not Null....then this Block start Executing }?.run {
This is Nullable But, where we Can put Warring } So, I am Suggest you Guys to Start Work in Kotlin with this Features Provided by Kotlin.
(Flied)?.let { Not Null Value Comes Under }?.run{ Null Value Code }
This will Handle to NullPoint Exception or Protect You App for Crash
What you want to achieve
What you want to achieve is that the Kotlin compiler does a smart cast on the variable you are working with.
In all of your three examples, the compiler can do that.
Example:
if(myVar != null) {
foo(myVar) // smart cast: the compiler knows, that myVar can never be null here
}
The choice
Which one of the options to use, is really a matter of style. What you should not do is mix it up to often. Use one and stick to it.
You don't need to worry about performance since let and run are inlined (see inline function). This means that their code (body) is copied to the call site at compile time so there is no runtime overhead.
I'm new to Kotlin and there's a common pattern that I'm not sure how to deal with most correctly. Take this code, for example, which doesn't compile:
git_repo?.add().addFilepattern()
add() is a call in the JGit library which is purely Java, so its return type is AddCommand!.
I have two options:
git_repo?.add()!!.addFilepattern("test.txt")
and
git_repo?.add()?.addFilepattern("test.txt")
Both work fine and given that
I don't know the intricacies of the library implementation,
the documentation of the JGit library doesn't specify whether add() can return null, and
within this context I'd typically expect add() to not return a null
Which version is more idiomatically correct to write in Kotlin? It seems that this would be a fairly common issue to deal with since basically every non-Kotlin library would introduce this issue.
I would use the ?. safe operator and then put your own exception at the end after an ?: Elvis operator. This way you get a message that is meaningful. Using just !! isn't a very helpful message to someone down the road who has no idea what the intricacies were either.
val cmd = gitRepo.add()?.addFilepattern("test.txt") ?: throw IllegalStateException("assert: gitRepo.add() returned an unexpected null")
cmd.doSomething() // never is null guaranteed
If the value is every null you will have a custom error.
assert: gitRepo.add() returned an unexpected null
And after this line, you will not have to null check because the result of the expression is guaranteed never to be null.
If you inspect the code of the other library and ensure it would never ever be null no matter what, then a !! is appropriate. But if not sure, do one better with the custom message.
Note I dropped the first ?. from your example because I'm assuming git_repo itself is not nullable. Plus I renamed it not to have an underscore which isn't normal Kotlin naming convention.
If you are sure that git_repo will always return a value!! is fine in that case.
It is ugly but !! will always be there when you use Java libraries, and you can't avoid it.
The only reason i would use git_repo?.add()?.addFilepattern("test.txt"), would be if you are returning a value, and you want the value to be nullable so that your calling method can handle the nullable.
fun nullableMethod(): string? {
return git_repo?.add()?.addFilepattern("test.txt")
}
fun callingMethod() {
if(this.nullableMethod() != null) {
}
//Else
}
If you are guaranteed it is never going to null, use !!
What does a single exclamation mark mean in Kotlin? I've seen it a few times especially when using Java APIs. But I couldn't find it in the documentation nor on StackOverflow.
They're called platform types and they mean that Kotlin doesn't know whether that value can or cannot be null and it's up to you to decide if it's nullable or not.
In a nutshell, the problem is that any reference coming from Java may be null, and Kotlin, being null-safe by design, forced the user to null-check every Java value, or use safe calls (?.) or not-null assertions (!!). Those being very handy features in the pure Kotlin world, tend to turn into a disaster when you have to use them too often in the Kotlin/Java setting.
This is why we took a radical approach and made Kotlin’s type system more relaxed when it comes to Java interop: now references coming from Java have specially marked types -- Kotlin Blog
It's the notation for platform types:
T! means "T or T?"
Platform Types
The type names or class names ending with single exclamation mark ! are called platform types in Kotlin. You find them when you are working in Kotlin with old Java code that doesn't contain nullability information.
Examples:
Nullable Information: Nullable Type
#Nullable String in Java is considered as String? by Kotlin.
Non-null Information: Non-null Type
#NotNull String in Java is considered as String by Kotlin.
No Information: Platform Type
String without annotations in Java is considered as String! by Kotlin.
How to deal with Platform Types?
You can work with a platform type either as a nullable or a non-null. The compiler will allow you to call all methods on this type. It’s your responsibility how to use them. If you know that the value can be null, you should compare it with null before you call methods on it. If you know it’s not null, you can use it directly but as in Java, you’ll get exception if your assumption about the nullability is wrong.
Note that you can't declare platform types in Kotlin code, they come only from Java code.
Inheritance and Platform Types
While overriding Java methods in Kotlin code, you have the option to declare parameters and return types as nullable or non-null. You need to choose this wisely, because if you decide to make the parameters non-null, the Kotlin compiler generates non-null assertions for these non-null parameters. And when next time you access this Kotlin code back from Java and you pass a null value, you'll get exception.
Hope that helps clearing all your doubts about Platform Types.
A Type notated with ! is called platform type, which is a type coming from Java and thus can most probably be null. It’s what the Kotlin compiler infers by default when calling Java (for the most basic cases, Java methods can be annotated to get around this). You should handle platform types as nullable types, unless you certainly know that the particular API will never return null. The compiler allows platform types to be assigned to variables of both nullable and non-null types.
Notation for Platform Types
[...]
T! means "T or T?" [...]
You could refer to platform types as "types of unknown nullability". Also important to know is that you cannot use the exclamation-marked type for your own types, it's not part of the Kotlin syntax, it's only a notation.
I use the funny interpretation to remember those things as below:
?: I dont know whether it is null or not.
!: Be careful! This might be null.
!!: Be careful, and yes I know it. This is always not null.
I've seen it a few times especially when using Java APIs
As mentioned by s1m0nw1, T! means T or T?. The next question is: what is T?? This is nicely documented at https://kotlinlang.org/docs/reference/null-safety.html. Kotlin does not allow certain elements to be null, e.g. String, unlike Java
To allow nulls, we can declare a variable as nullable string, written
String?:
var b: String? = "abc"
b = null // ok
[...]
b?.length
This returns b.length if b is not null, and null otherwise. The type of this expression is Int?.
Excerpt from Platform Types in Kotlin :
Besides explicitly specifying a type as optional (e.g. Person?), Kotlin presents us with another beast, called Platform Type, specified by putting a single exclamation mark instead (e.g. Person!). This concept has been created for compatibility reasons, when accessing code from null-unsafe platforms like Java. It is often the case that when using a Java library, many methods return SomeType!, since the Kotlin compiler cannot infer if the result is nullable or not.
For example:
(Mutable)Collection<T>!
Just means the following: "Java collection of T may be mutable or not, may be nullable or not".
Hope this helps.