If a variable is nullable in Kotlin, we need to either do a safety call ?., or !!. for explicitly call.
When I was trying to use some extensions(such as run or let) from nullable variable , I noticed that .run is fine and IDE did not complain it, usually I will receive a warning to remind me it is not a safety call.
Does it make any difference for ?.run{} and .run{} in kotlin? Is it considered as null safety if I use .run{} ?
var a? = "..."
a?.run{}
a.run{}
You'll need to safely handle the null somewhere.
Either when accessing a:
a?.run { }
Or when accessing this inside run on a:
a.run { this?.toSomething() }
Using a String? as an example, these both print null and the compiler is ok with both:
val x: String? = null
println(x.run { this?.toUpperCase() }) // prints null, type is String?
println(x?.run { this.toUpperCase() }) // prints null, type is String?
Related
I want to know the difference between String? and String! in Kotlin.
I search on kotlinlang.org but did not find any information.
Kotlin's type system differentiates between nullable and non-nullable types. In that context, String? is a nullable type while String would be the corresponding non-nullable type.
When working with Java libraries, the compiler is not always able to identify whether a type is nullable or not, since Java does not have that differentiation. Such types will then show up as "platform type" String!, meaning (basically): "I have no idea if this can be null but I'll treat it as non-nullable for now".
If you have control over the corresponding Java library, Kotlin supports various annotations to help distinguish between types, otherwise it is up to you as developer to explicitly assign either a nullable or a non-nullable type e.g. upon variable declaration to avoid running into NullPointerExceptions at runtime.
I'll try to answer with some sample code.
1. String?
This means this string is nullable.
Example 1: Use it in the type definition.
fun testStringTypes() {
// When initializing stringA, we can set null as the value
var stringA: String? = null
// And we can also set it to a meaningful string
stringA = "Hello"
// Then we can still set it back to null
stringA = null
}
Example 2: a variance of String?
fun testStringTypes() {
var stringA: String? = null
stringA = "Hello"
stringA = null
val lenOfStringA = stringA?.length ?: 0
}
So here is a brief description about what this val lenOfStringA = stringA?.length ?: 0 means:
Because stringA is defined as nullable;
stringA?.length means, access to the length property only if stringA is not null;
Because if, when stringA is null and if the code still tries to access to length (like in Java), the program will throw a NullPointerException. stringA? a question mark here, is to avoid this, which is called SafeCalls.
2. String!
This is platform types.
Copy from the link above:
As mentioned above, platform types can't be mentioned explicitly in the program, so there's no syntax for them in the language. Nevertheless, the compiler and IDE need to display them sometimes (for example, in error messages or parameter info), so there is a mnemonic notation for them:
I think (correct me if I was wrong), this makes sense when working with Java, because String in Java can be null, in other words, when accessing it from Kotlin, we don't know it is null or not. So String! is kind of a reminder to developer: Hey! Attention, this variable could be null.
Example 3, work with Java method from Kotlin:
// In Java:
public class PlatformTypeTest {
public String returnSomeStringCouldBeNull() {
return null;
}
}
And let's call this method in Kotlin.
fun testStringTypes() {
val someStringFromJava = PlatformTypeTest().returnSomeStringCouldBeNull()
}
fun testStringTypes() {
val someStringFromJava = PlatformTypeTest().returnSomeStringCouldBeNull()
someStringFromJav
}
As we can see from above two screenshots, IDE is reminding us this String from Java can be null.
And for String!, we can access it in different ways:
fun main() {
val someStringFromJava = PlatformTypeTest().returnSomeStringCouldBeNull()
var lenOfString = someStringFromJava?.length ?: 0
// lenOfString = someStringFromJava.length // NullPointerException
// lenOfString = someStringFromJava!!.length // NullPointerException
println(lenOfString)
}
With code snippet above, it works fine with var lenOfString = someStringFromJava?.length ?: 0, but the other two ways will cause NPE, as explained at above.
String? is a nullable type.
String! is a platform type platform type.
From Kotlin website:
Nullable Types Example:
val nullable: String? = item // allowed, always works
val notNull: String = item // allowed, may fail at runtime
Platform Types Example:
- T! means "T or T?",
- (Mutable)Collection<T>! means "Java collection of T may be mutable or not, may be nullable or not",
- Array<(out) T>! means "Java array of T (or a subtype of T), nullable or not"
I'm on learning basics of Kotlin language for Android Development :), i'm looking on some Kotlin syntax examples and i found out this example below.. the thing that i don't know what is purpose with the ? code.. i'm trying to find on Google but i can't understand completely what they explain, maybe you can help me with your explanation / your example on this one ? I'll appreciate that :)
Example :
fun main() {
val myName :String? = "Maura"
println("Your name is $myName")
val myAge :Int? = 18
println("Your age is $myAge")
}
Its null safety. Basically Int? represents nullable Int, while Int on its own is non-null.
var a: Int = 5
a = null // error
var b: Int? = 5
a = null // :)
In case you have null in your code, you cannot use them directly, if you want to for example call any function in them you have to follow null-safety: Use ?. safecall operator, or !!. null assertion operator (usually shouldn't use).
val c = a.plus(4) // :)
val d = b.plus(4) // Hold on, I'm null you can't use "." on me :P
val e = b?.plus(4) // Ok, if b is not null, add 4 and store that to e, otherwise store null to e
val f = b!!.plus(4) // Hmm, if b was not null I'll add 4 to it and store to f, otherwise I'll crash your program throwing NPE
In contrast to this the type of e would be Int? as you've already read the thing. But what if you want to assign it a default value, easy use the elvis operator (?:):
val g = b?.plus(4) ?: 4 // if b is not null add 4 to it and store otherwise store 4 :)
Edit: The code in your sample works because there's String template calls .toString() and it is defined as fun Any?.toString() i.e. defined on a nullable receiver. So b.toString is valid though can be confusing.
println("Your age is $myAge")
// is same as
println("Your age is" + myAge.toString())
// toString is an extension function valid for nullable types, though member functions aren't :)
well, this is null safety feature of Kotlin lang (awesome btw.)
in short: ? next to type of variable/value means that this variable/value may be null. don't use it so often, it kind-of protects you from NullPointerExceptions, pretty often bug-cause in Java. also in your simple case it is unnecessary
var myName :String? = null // this is possible
var mySecondName :String = null // this isn't possible, build error
var myThirdName :String = "never null"
myThirdName = null // build error, this variable can't be null
myName = myName.replace("a", "b")
// build error above, trying to access nullable variable straightly
myName = myName?.replace("a", "b")
// null safety with ?, if myName is null it won't be executed and myName stay null
myThirdName = myThirdName.replace("a", "b") // this is possible
myThirdName = myThirdName?.replace("a", "b")
// this is also possible, but you will get a warning that ? is unnecessary
I'm creating one function in Kotlin. It validates email and password fields. I want to apply email and password should not be null. #NotNull kinda annotation here.
Does anyone know how to do this in Kotlin? So the caller cannot send the null value.
private fun isEmailAndPasswordValid(email: String, password: String): Boolean {
if (email.isEmpty()) return false
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) return false
if (password.isEmpty()) return false
return true
}
Kotlin differentiates all types by nullable and not-nullable. For example, the class String can be used for the type String, which is not nullable, and the type String?, which IS nullable, i.e. could hold null.
In your example no nullable types are used, so you’re all good - no additional annotation needed.
The documentation should be studied for further information.
The Kotlin language is by default null-safe so when creating a new variable it can't be null, but when you want a nullable variable you can add The exclamation mark to specify that it can be null for Example String?, Int? ...
Not Nullable
var a: String = "bachiri"
a = null // compilation error
Nullable Type
var a: String? = "bachiri"
a = null // OK
and bare in mind if you want to call a function on the nullable Type you should use eighter the check for null variable(1) or use the safe calls(2)
Kotlin has build-in null safety. String is a non-null type while String? is a nullable type. So, isEmailAndPasswordValid(email: String, password: String) will enforce the value passed to it is non-null.
When I check the Kotlin documentation, I can see that a String variable can't be set to null, unless you declare it can be, and your compiler will raise an error.
For example, a regular variable of type String can not hold null
https://kotlinlang.org/docs/reference/null-safety.html
I am confuse for lateinit and nullable variable, which one to use for variable.
lateinit var c: String
var d: String? = null
c = "UserDefinedTarget"
// if not added initialisation for c than throws UninitializedPropertyAccessException
if (c == "UserDefinedTarget") {
//do some stuff.
}
//not throws any exception whether d is initialise or not.
if(d == "UserDefinedTarget") {
//do some stuff
}
A type that is nullable is just that, a thing that has a valid state that is null.
A non-nullable late init var represents something where null is an invalid state, but for some reason you can't populate it in the constructor.
Android Activities are a good example of a use of lateinit. Activities must have a no args constructor and their lifecycle only really starts with onCreate().
These are two completely different concepts.
You can use lateinit to avoid null checks when referencing the property. It's very convenient in case your properties are initialized through dependency injection, or, for example, in the setup method of a unit test.
However, you should keep in mind that accessing a lateinit property before it has been initialized throws an exception. That means you should use them only if you are absolutely sure, they will be initialized.
Nullable types, on the other hand, are used when a variable can hold null.
class A {
lateinit var a: String
fun cat() {
print(a.length) // UninitializedPropertyAccessException is thrown
a = "cat"
print(a.length) // >>> 3
}
}
class B {
var b: String? = null
fun dog() {
print(b.length) // won't compile, null check is obligatory here
print(b?.length) // >>> null
b = "dog"
print(b?.length) // >>> 3
}
}
For more information:
Late-initialized properties
Nullable types
It depends.
Nullable variable means that variable can hold value or null. lateinit means that variable must be initialised later. It should be initialized before accessing it. If you attempt accessing uninitialized lateinit variable UninitializedPropertyAccessException will be thrown.
It's always better to avoid using nulls in your app. Nulls are evil. So if you can initialize variable in onCreate then it's better to use lateinit. Also if you use dependency injection in your app and fields should be injected it's also a valid case to use lateinit instead of handling nulls.
If for some reason you can't initialize variable, initializing code can result to null, or null can be assigned to this variable later than you should use nullable variable. Generally speaking if null is a valid value for the variable.
Use lateinit for properties that cannot be initialized in a constructor.
I'm new to Kotlin and I don't know why compiler complains about this code:
data class Test(var data : String = "data")
fun test(){
var test: Test? = Test("")
var size = test?.data.length
}
Compiler complains with test?.data.length, it says that I should do: test?.data?.length. But data variable is String, not String?, so I don't understand why I have to put the ? when I want to check the length.
The expression test?.data.length is equivalent to (test?.data).length, and the test?.data part is nullable: it is either test.data or null. Therefore it is not null-safe to get its length, but instead you should use the safe call operator again: test?.data?.length.
The nullability is propagated through the whole calls chain: you have to write these chains as a?.b?.c?.d?.e (which is, again, equivalent to (((a?.b)?.c)?.d)?.e), because, if one of the left parts is null, the rest of the calls cannot be performed as if the value is not-null.
If you don't want to use safe call before each non-nullable component of the call chain, you can get the result of the first safe call into a new variable with the standard extension functions run or let:
// `this` is non-nullable `Test` inside lambda
val size = test?.run { data.length }
// or: `it` is non-nullable `Test` inside lambda
val size = test?.let { it.data.length }
Note that size is still nullable Int? here.