I have a function for validating the request, it can't be null or empty, I can test if the end point is empty, but I can't pass the value as null to the request in test, I will get "NulllPointerException", how can I test null case?
fun validateRequest(request: RegisteRequest) {
validateEndPoint(request.EendPoint)
}
private fun validateEndPoint(endPoint: String) {
if (endPoint.isNullOrEmpty()) {
logger.error("Request is missing EndPoint")
throw IllegalArgumentException(ERROR_MESSAGE_MISSING_END_POINT)
}
}
Kotlin's type system is able to differentiate between values that can be null (e.g., String?) and values that can't be null (e.g., String). You can find more details here.
In your case you're defining a function that takes in input a non-null String, so if you're invoking it from Kotlin, the Kotlin compiler will make sure you don't pass a null value – it'll fail the build if you try to do so.
If somehow you still manage to pass a null value (e.g., via reflection or by invoking the function from Java), you'll get a NullPointerException (as documented here), because the Kotlin compiler will actually insert some instructions under the hood to make sure you don't provide a null value.
So if your code is meant to be called from Java or if you really want to test what happens if you pass null, you'll have to assert that a NullPointerException is thrown.
If, instead, null is a valid value and you want to handle it differently, you'll have to change the signature of your method so that it accepts a null parameter (note the type of the parameter here is String?):
private fun validateEndPoint(endPoint: String?) {
...
}
Related
Is it possible to define a function in Kotlin where you can either return something or return nothing? I thought maybe to use Any as the return type, but that still requires the function to return something, although perhaps there is a way to return a Unit when the return type is Any?
I also found "Nothing":
Nothing has no instances. You can use Nothing to represent "a value that never exists": for example, if a function has the return type of Nothing, it means that it never returns (always throws an exception).
Unfortunately that will throw an exception. That's too bad. I wonder why they throw an exception?
You can wrap the result in a sealed class
sealed class Result<out T> {
data class Success<out T>(val value: T): Result<T>()
object Failure: Result<Nothing>()
}
Then for calling it you can
fun <Type>calculateResult(...): Result<Type> {
//calculate and return some implementation
}
And then
val result = calculateResult(inputs)
when (result) {
is Success -> {
val value = success.value
}
is Failure -> {
//Do something like show an error the user you know your value is Nothing
}
}
You can just use a nullable return type.
Otherwise, to address whether you can return Unit, you can. Unit is just a Kotlin object so you can get the instance by name:
return Unit
However I wouldn't recommend it, there are plenty of better options.
In regards to Nothing, it is a special type that is used to represent a function never returning. So if I wanted to write a function that throws an exception, I could do so with the Nothing return type. Then the inference engine knows that nothing past my function call will get executed.
Well if you think about it, a function can't return something or nothing, because what's the result of calling it? Do you have a value, or nothing at all? If you assign the result to a variable, but there is no result, that variable has no value, so what is it? The function has to either be defined as always returning something or always returning nothing, so you always know if there's a return value and what its possible types are. Otherwise we're getting into philosophical territory!
In fact in Kotlin, functions always return something - if you don't specify a type, like a void function in Java, it will default to returning Unit. This is a special value that represents a function not returning a result, but it is still a result type that gets returned. It's not nothing, it's a a thing. Every function has to return a thing.
So if you want to define the thing you return as either "a value that represents a thing" or "a value that represents nothing", you need a type that is capable of expressing both those ideas. You have three basic approaches I think:
use a specific value to represent "no value", e.g. -1 for an Int, "NO_VALUE" for a String, that kind of thing
create a type that defines a "no value" version of itself, like the Result type in one of the answers, the Optional type in Java, etc
just use null because nullable versions of every type are built into Kotlin's type system, and the standard library is geared towards handling them. Check out these features built around working with nulls
Use the nullable types IMO - return a String? or whatever and if the result is non-null, do something with the value. If it is null, ignore it. Kotlin makes that pretty easy! If you get to the point where you need to roll a special type, you'll probably know why you need it over your good friend null
Just learned Kotlin Nullable type and let{} function which replaces the if (xx != null) {} operation.
But one thing I am confused is that, we all know and I Think the Complier Should Know that when we use let{}, the variable/object who is calling this function is possiblly null, however the complier still requires me to add the safe call operator "?" after the variable name instead of providing Smart Cast like it does in if (xx != null) {}. Why?
My piece of code:
fun main() {
var number1: Int? = null
//val number2 = number1.let { it + 1 } ?: 10 //doesn't work, not quite "smart"
val number2 = number1?.let { it + 1 } ?: 10 //works, must have "?"
println(number1)
println(number2)
}
You've already got answers in the comments, but just to explain the ? thing...
Kotlin lets you make null-safe calls on nullable variables and properties, by adding ? before the call. You can chain this too, by doing
nullableObject?.someProperty?.someFunction()
which evaluates nullableObject, and if it's non-null it evaluates the next bit, otherwise the whole expression evaluates to null. If any part of the chain evaluates as null, the whole expression returns null.
So it has this short-circuiting effect, and you can use the elvis "if null" operator to create a default value if you can't evaluate the whole chain to a non-null result:
nullableObject?.nullableProperty?.someFunction() ?: defaultAction()
and once you introduce the null check in the chain, you have to add it for every call after that - it's basically propagating either the result of the previous bit, or the null it resolved to, so there's a null check at each step
The let block is just a scope function - you use it on a value, so you can run some code either using that value as a parameter or a receiver (a variable or this basically). It also has the side effect of creating a new temporary local variable holding that value, so if the original is a var it doesn't matter if that value changes, because your let code isn't referring to that variable anymore.
So it's useful for doing null checks one time, without worrying the underlying value could become null while you're doing stuff with it:
nullableVar?.let { it.definitelyIsNotNull() }
and the compiler will recognise that and smart cast it to a non-null type. An if (nullableVar != null) check can't guarantee that nullableVar won't be null by the time the next line is executed.
Question is simple:
In Kotlin, when I instantiate a fragments arguments with a Bundle(), the system still needs the arguments object to be reassured with !!. The arguments should be definitely not null by now, right? So why is that needed?
Here is the code:
private fun openPinCodeFragment(mode: PinView.Mode) {
currentFragment = PinCodeFragment()
currentFragment?.run {
arguments = Bundle()
arguments!!.putSerializable(MODE, mode)
}
openFragment(currentFragment)
}
If I remove the !! then:
You're setting the value of a variable which was defined outside of this scope (the declaration of arguments is not visible in your code).
No matter what you assign, it could have been changed by the time code execution reaches the next line to a null value by another Thread, that's why you have to use the !! here. I'd suggest defining arguments either in local scope with val or making it non-nullable in its definition.
This happens because arguments is of Bundle? type, this means that it can be either Bundle or null.
Instead of using an if to check whether it is null, like you would to in Java, the operators !! and ? were introduced.
For example if you want your code to be correct without using !! you could add:
if (arguments != null) {
arguments.putSerializable(MODE, mode)
}
Using these operators you have the following flexibility:
!! - you tell the compiler that the value cannot be null, it will throw error otherwise;
? - you don't care that much, if it is not null then it will access method and might return result, otherwise the result of such call is null and no action is made.
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 !!
I want to call a overloaded java-function from Kotlin. I want to use a null for parameter that significant to a overload resolution.
How to specify IntArray type for null value?
I don't like a solution with additional varibale of common type.
Instead of a variable just cast it, i.e. null as IntArray?, e.g.:
origImg.data.getSamples(0, 0, origImg.width, origImg.height, 0, null as IntArray?)
Note that this is the same behaviour as in Java, where you also needed to cast null, e.g. (int[]) null, to call the appropriate overloaded method.
You could build a function that gives you a ~typed null (if it doesn't exist yet) with a reified type:
inline fun <reified T>typedNull(): T? = null
and calling it with:
typedNull<IntArray>()
But then again, null as IntArray? is clear enough I think and people know it already.