In java we can call a method aMethod(val1 , val2)
with classObject.aMethod(null_if_Val1_NotAvailable,val2)
And inside the Method i will check that if val1 is null
i will initialize that
How to do the same in Kotlin.
I tried but its saying Null Cannot be value of Non-null type
You can use default values:
fun aMethod(val1: String = "default value", val2: String)
You can now use the default method like so:
classObject.aMethod(val2 = "val2")
Try it this way
fun printHello(name: String?): Unit {
if (name != null)
println("Hello ${name}")
else
println("Hi there!")
// `return Unit` or `return` is optional
}
Return type as your wish.
Refrence from kotlin langauge function tutorial
? after the datatype allows you to have null. refer this link
Kotlin emphasis on null safety. If you want a property/return type/parameter/local variable to be null, you will have to use nullable types, by appending a question mark to the end of your type.
e.g.
Foo foo = null // doesn't compile
Foo? foo = null // compiles
fun foo(foo: Foo)
foo(null) // doesn't compile
fun bar(foo: Foo?)
bar(null) // compiles
fun foo(): Foo = null // doesn't compile
fun foo(): Foo? = null // compiles
So in order to make your code works, all you need is to specify that function aMethod takes a nullable type:
fun aMethod(val1: SomeType?, val2) {
//...
}
However, in kotlin, it's not suggested to use null here. We have a better way to deal with your situation. We use default parameters, as suggested by nhaarman.
fun aMethod(val1: SomeType = someDefaultValue, val2: OtherType) {
//...
}
aMethod(val2 = OtherType())
Related
Why this code is giving me the NPE error?
fun main() {
val myObj: MyObj? = null
print(myObj?.someVal!!)
}
class MyObj{
val someVal = 1
}
Does non-null assertion evaluate the whole expression before? I thought that myObj? should be enough to print null here.
Yes. When you use a null-safe call, the expression is evaluated to null if the receiver is null, so
myObj?.someVal!!
behaves the same as
(if (myObj != null) myObj.someVal else null)!!
(If myObj is a property rather than local variable, these aren't equivalent, since smart-casting wouldn't work.)
Simple example:
This code will print null:
fun main() {
val myObj: MyObj? = null
val someVal = myObj?.someVal
print(someVal)
}
This code will throw NPE as the variable is null:
fun main() {
val myObj: MyObj? = null
val someVal = myObj?.someVal
print(someVal!!)
}
I'm working on extension method like this:
infix fun <T> T.isNullOr(other: T): Boolean {
if (this == null) return true
return this == other
}
and I'm trying to use this method like this.
val thisShouldWork = true isNullOr true // this is true
val thisShouldNotWork = true isNullOr 0 // No compilation errors?
I expected compilation error because type parameter is automatically set to Boolean for isNullOr but it wasn't. What's happening?
am I misunderstanding about it?
in C#, same code working well as I expected.
static bool IsNullOr<T>(this T t, T other) {
if (t == null) return true;
return Equals(t, other);
}
bool howAboutThis = 0.IsNullOr(0);
bool andThis = 0.IsNullOr(false); // error - cannot detect type parameter for this
Here, val thisShouldNotWork = true isNullOr 0 is equal to val thisShouldNotWork: Boolean = true.isNullOr<Any>(0). Type parameter as inferred as the closest parent.
And function's return type is based on logical expression evaluation: this == other. Let's see == function declaration: public open operator fun equals(other: Any?): Boolean. It receives Any?.
Type parameter in this function has nothing to do with Boolean.
Just remember that generic type information is erased at runtime and whenever you try to put something into a method that accepts generics, then the common denominator is assumed, e.g.:
listOf("one", 123) // -> assumes T:Any and therefore gives List<Any>
Now for your example that would mean "one".isNullOr(123) both become Any.
As a sidenote however, if you declare a specific type (e.g. List<String>) as shown next, it will not work to assign a different type to it:
val test : List<String> = listOf(123) // this will not work
It is already known at compile time that the given int can't become a string. This sample however doesn't help you as you do not return that generic type. If your method just looked a bit different, e.g. would have a generic type as return value, it might easily have worked out similar to the List-sample before.
So to fix your sample you need to specify the type which will basically make the infix obsolete, e.g. the following will work as you expect:
val someString : String? = TODO()
val works = someString.isNullOr<String?>("other")
val doesntWork = someString.isNullOr<Int?>(123) // does not nor does:
val doesntWorkToo = someString.isNullOr<String?>(123)
Note that for what you've shown some standard functionality might help you (but not eliminate that specific problem), i.e. using the ?: (elvis operator) with a ?.let:
val someVal : String? = "someString given from somewhere"
val thisWorks = someVal?.let {
it == "some other string to compare"
} ?: true /* which basically means it was null */
val thisWillNot = someVal?.let {
it == 123 // compile error (funny enough: it.equals(123) would work ;-)
} ?: true /* it is null */
I think in this case the generics don't really matter. You only call equals in the method, which you can do on any type. It's basically the same as:
infix fun Any.isNullOr(other: Any): Boolean {
return this == other
}
It compiles without problems because you can always call equals with anything: other: Any?
Thank for answers. I think there is no way to prevent this at compilation level, so I decided to check type for other.
inline infix fun <reified T> T.isNullOr(other: T): Boolean {
if (this == null) return true
if (other !is T) return false
return this == other
}
If you really want to prevent it, you can:
class IsNullOr<T>(val x: T) {
operator fun invoke(other: T): Boolean {
if (x == null) return true
return x == other
}
}
fun <T> T.isNullOr() = IsNullOr(this)
fun main(args: Array<String>) {
val thisShouldWork = true.isNullOr()(true) // compiles
val thisShouldNotWork = true.isNullOr()(0) // doesn't compile
}
This makes type inference depend only on the receiver of isNullOr. If vals could be generic, you'd even keep the original syntax (but they can't).
I want a class which is equivalent to Java Optional but also
Properly handles null value ("Not set" state is different from "Null set")
Is mutable
Uses Kotlin built-in null-safety, type parameter can be either nullable or non-nullable which affects all methods.
Non-working code:
class MutableOptional<T> {
private var value: T? = null
private var isSet: Boolean = false
fun set(value: T)
{
this.value = value
isSet = true
}
fun unset()
{
isSet = false
value = null
}
fun get(): T
{
if (!isSet) {
throw Error("Value not set")
}
return value!! // <<< NPE here
}
}
fun f()
{
val opt = MutableOptional<Int?>()
opt.set(null)
assertNull(opt.get())
}
The problem is that if I try to set null, get() call fails with null pointer exception (caused by !! operator).
Some not-working proposals:
Do not use members of type "T?" in such class. I would not use it if I knew how to leave them uninitialized (not allowed by the compiler) or how to make them to have default initialization.
Use "fun get(): T?" (with nullable result). I want the result type to have the same nullability as the class type parameter. Otherwise there is no meaning in such null-safety if it is lost in a simple generic class, and I will need to set !! manually where I am sure it is non-nullable (the thing the compiler should ensure), making my code looking like wedge-writing.
Note: This example is synthetic, I do not really need the mutable optional, it is just a simple and understandable example, illustrating a problem I encounter occasionally with Kotlin generics and null-safety. Finding solution to this particular example will help with many similar problems. Actually I have a solution for immutable version of this class but it involves making interface and two implementation classes for present and non-present values. Such immutable optional can be used as type of "value" member but I think it's quite big overhead (accounting also wrapper object creation for each set()) just to overcome the language constraints.
The compiler wants you to write code that will be type-safe for all possible T, both nullable and not-null (unless you specify a not-null upper bound for the type parameter, such as T : Any, but this is not what you need here).
If you store T? in a property, it is a different type from T in case of not-null type arguments, so you are not allowed to use T and T? interchangeably.
However, making an unchecked cast allows you to bypass the restriction and return the T? value as T. Unlike the not-null assertion (!!), the cast is not checked at runtime, and it won't fail when it encounters a null.
Change the get() function as follows:
fun get(): T {
if (!isSet) {
throw Error("Value not set")
}
#Suppress("unchecked_cast")
return value as T
}
I got a similar issue. My use case was to differentiate null and undefined value when I deserialize JSON object. So I create an immutable Optional that was able to handle null value. Here I share my solution:
interface Optional<out T> {
fun isDefined(): Boolean
fun isUndefined(): Boolean
fun get(): T
fun ifDefined(consumer: (T) -> Unit)
class Defined<out T>(private val value: T) : Optional<T> {
override fun isDefined() = true
override fun isUndefined() = false
override fun get() = this.value
override fun ifDefined(consumer: (T) -> Unit) = consumer(this.value)
}
object Undefined : Optional<Nothing> {
override fun isDefined() = false
override fun isUndefined() = true
override fun get() = throw NoSuchElementException("No value defined")
override fun ifDefined(consumer: (Nothing) -> Unit) {}
}
}
fun <T> Optional<T>.orElse(other: T): T = if (this.isDefined()) this.get() else other
The trick: the orElse method have to be defined as an extension to not break the covariance, because Kotlin does not support lower bound for now.
Then we can define a MutableOptional with no cast in the following way:
class MutableOptional<T> {
private var value: Optional<T> = Optional.Undefined
fun get() = value.get()
fun set(value: T) { this.value = Optional.Defined(value) }
fun unset() { this.value = Optional.Undefined }
}
I am happy with my immutable Optional implementation. But I am not very happy with MutableOptional: I dislike the previous solution based on casting (I dislike to cast). But my solution creates unnecessary boxing, it can be worst...
I have a data class
data class MyModel(private val _data: MyData? = null)
And I want to ensure my data is only accessible when it is not null, else throw.
I use the below which is good.
fun getData(): MyData {
return checkNotNull(_data) { "data shouldn't be null" }
}
However, if I follow the guide as per Override getter for Kotlin data class, the below complaints I need to return MyData? instead of MyData
val data = _data
get(): MyData {
return checkNotNull(field) { "data shouldn't be null" }
}
Is it true that field can't be cast to the Non-null version of it when return?
If your goal is to declare a getter for a Any? property that returns a Any, it's not possible. You'll get the following error:
Getter return type must be equal to the type of the property
So attempting to do something like
val test : String?
get() : String = "hi"
Wouldn't work.
However, you could hide the nullable property and expose a non-nullable property which references the nullable value via casting:
private val test : String? = "hi"
val testNotNull : String = test as String
If test referenced null, an exception will be thrown.
For example:
fun main(args: Array<String>) = print(Demo().testNotNull)
class Demo(private var test: String? = "hi") {
val testNotNull : String
. get() = test as String
}
You can test this snippit out at try.kotlin.org
Although this is not safe. You should rethink your design. If you're not interoping with Java, you shouldn't punish yourself with nullable types.
I don’t think you can. What you did with the fun getData() is a valid approach IMO. Or you could just not use a data class and create a normal class, obviously.
What I think it may work is with something like this:
typealias notNullType = MyData
data class Test(private val _value: MyData? = null) {
val v: notNullType = _value as notNullType
get() { return field }
}
This would totally allow you to do:
fun play() {
val t = Test(null)
print(t.v) //see what I did? :-)
}
THAT BEING SAID… I don’t think “hiding” the ? optional is necessarily a good idea.
It doesn't necessarily mean that the MyData class is null if you cast it like MyData?
The '?' Just allows the object to be null in the instance that it actually becomes null to avoid an exception at runtime.
You can make your class nullable and it can still contain your data.
How do I handle a nullable generics Class type in Kotlin?
Example function with generics:
fun <I> calculateStuff(valueType: Class<I>, defaultValue: I): I {
// do some work
return defaultValue;
}
Here is a calling function (note the 2nd param for calculateStuff(...))
fun doStuff() {
// works fine!
val myVar1 = calculateStuff(String::class.java, "")
// FAIL (null is not accepted... Error: "Cannot infer type parameter I in....")
val myVar2 = calculateStuff(String::class.java, null)
}
Work-around (change return type to I? AND defaultValue to I?):
fun <I> calculateStuff(valueType: Class<I>, defaultValue: I?): I? {
return defaultValue;
}
Preferred method, but does not seemed supported by Kotlin (note "String?::class.java"):
val myVar2 = calculateStuff(String?::class.java, null)
I really want to be able to send to the method (calculateStuff(...)) the return type, and if it can be null, as the first parameter... that way I ONLY have to null-check the return value if I pass a nullable Class in the first param.
Is this possible to do in Kotlin?
You need to change Class<I> to Class<out I>:
fun <I> calculateStuff(valueType: Class<out I>, defaultValue: I): I {
return defaultValue;
}
You can also do this using reified type parameters:
inline fun <reified I> calculateStuff(defaultValue: I): I {
// do some work
return defaultValue;
}
Usage:
val myVar1 = calculateStuff("") // myVar1 is String
val myVar2 = calculateStuff<String?>(null) // myVar2 is String?
Since there is no way to specify nullable classes as you discovered, your premise of limiting it by the first variable is not possible.
What is possible is to limit it by the nullability of the second variable by adding a second generic parameter:
fun <I, NI: I> calculateStuff(valueType: Class<NI>, defaultValue: I): I {
// do some work
return defaultValue;
}
val myVar2 = calculateStuff(String::class.java, null as String?) will now compile.
The reason this works is because in the kotlin type system, T is a subclass of T? so any non-nullable value is an acceptable value for a nullable type.