Kotlin number boxing test strange [duplicate] - kotlin

This question already has an answer here:
kotlin int boxed identity
(1 answer)
Closed 4 years ago.
I am a beginner of kotlin.
I do not understand the output below.
#Test
fun testNumberBoxing() {
val a:Int = 1000
val boxedA1: Int? = a
val boxedA2: Int? = a
println("first check = ${boxedA1 === boxedA2}")
val b: Int = 2
val boxedB1: Int? = b
val boxedB2: Int? = b
println("second check = ${boxedB1 === boxedB2}")
}
result is
first check = true
second check = false
Why are the two outputs different?
my kotlin version is 1.2.31
org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.31

The output I got
first check = false
second check = true
What the code compiles to
public static final void main(#NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
int a = 1000;
Integer boxedA1 = Integer.valueOf(a);
Integer boxedA2 = Integer.valueOf(a);
String var4 = "first check = " + (boxedA1 == boxedA2);
System.out.println(var4);
int b = 2;
Integer boxedB1 = Integer.valueOf(b);
Integer boxedB2 = Integer.valueOf(b);
String var7 = "second check = " + (boxedB1 == boxedB2);
System.out.println(var7);
}
Why valueOf is not consistent
For this we need to look at the JavaDoc of valueOf:
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
As you can see, for small values it will return the same object on both calls, so they are equal, and for the larger uncached value the 2 objects are different
In java the == checks for object equality, so the 2 equal objects are false, while 2 copies of the same object returns true.

That's rather weird, I'm consistently (both locally and on try.kotlinlang.org with different Kotlin versions) getting this result instead:
first check = false
second check = true
And this is what is to be expected, as the JVM caches Integer instances int the -127 to 128 range, reusing the same Integer instance when one is required for boxing, literals, or Integer.valueOf calls in this range.

In contrast to php or javascript where === is in most cases the more sane option, in Kotlin === compares references to objects instead of values.
As others pointed out, objects for Integers of the same value can be cached. Same goes for Strings and the other primitive types.

Related

can't get Kotlin to check if variable in listOf

I've tried this 10 different ways and i can't get this to work.
I want this Kotlin code to take in a string, check each character of that string against a listOf characters, and, if it is in that list, increase a counting variable by 1, so then at the end it can check if that counting variable is high enough to pass a test. this is taken straight from Sololearn: Code Coach - Password Validator. I have completed this code successfully already in Python (https://code.sololearn.com/c0fl17IMHPfC), but in trying to convert it over to Kotlin, it doesn't seem to work. The variables don't seem to register as true when compared to the elements in the listOf.
fun main() {
var password: String = readLine()!!
var numberCount: Int = 0
var numbers: List<String> = listOf("0","1","2","3","4","5","6","7","8","9")
var specialCount: Int = 0
var specialCharacters: List<String> = listOf("!","#","#","$","%","&","*")
if (password.length < 7) {
println("Weak")
} else {
for (character in password) {
println(character)
var numberCheck = numbers.contains(character)
println(numberCheck)
if (numberCheck == true) {
numberCount += 1
}
var specialCharactersCheck = specialCharacters.contains(character)
println(specialCharactersCheck)
if (specialCharactersCheck == true) {
specialCount += 1
}
}
println(numberCount)
println(specialCount)
if (numberCount < 2) {
println("Weak")
} else if (specialCount < 2) {
println("Weak")
} else {
println("Strong")
}
}
}
When I enter an input of "letssee43$#", the result of this code is:
l
false
false
e
false
false
t
false
false
s
false
false
s
false
false
e
false
false
e
false
false
4
false
false
3
false
false
$
false
false
false
false
0
0
Weak
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.
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.
Your list is a list of Strings, but for (character in password) loops over the Chars in password. So you're trying to see if one of the Strings in your list is a specific Char, which it isn't, because they're two different types - a string with a single character in it is still a String, not a Char (that's why you're getting that type error)
There are lots of ways to do it (and there's nothing wrong with your code besides the Char/String thing!), personally I'd just do this:
var numbers = "0123456789"
var specialCharacters = "!##$%&*"
val password = "letssee43$#"
val nums = password.count { it in numbers }
val specials = password.count { it in specialCharacters }
println("nums: $nums, specials: $specials")
> nums: 2, specials: 2
count is iterating over the Chars in password and counting how many of them each character string contains. A String is treated like an array of Chars, so you can check it that way. (You could also add .toList() after the string declaration if you really want your characters stored in a list - that way it'll be a List<Char> so the lookup will still work.)
Or you could do things the way you are, and explicitly write out the listOf elements - but make them Chars instead, e.g. listOf('1') (single quotes) instead of listOf("1") (double quotes).
If you do want to search a list of strings for a match, you need to provide a String, so you need to convert your Char to one, e.g. by calling toString() on it, using a literal like "$character", etc.
edit like gidds points out below, sets are way more efficient for lookups like in or contains, so toSet() is a better idea than toList() unless you really need that ordered list for some reason. If you don't care about efficiency (like if you're not doing a lot of lookups) I'd personally just leave it as a string like in the code block up there - it's nice and simple. But if you do want to be more efficient, or if you do need a collection (like if you're matching against Strings) then a Set is ideal
I will give you another way to get the same result as you by using Extensions
fun main() {
var password: String = readln()
println("Password contain numbers amount: " + password.containNumbersAmount())
println("Password contain special characters amount: "+ password.containSpecialCharactersAmount())
println("Password Status : "+ password.validationResult())
}
fun String.containNumbersAmount() = count { it.isDigit() }
fun String.containSpecialCharactersAmount(): Int {
val specialCharacters = "!##$%&*"
return count { it in specialCharacters } }
fun String.validationResult() : String {
return when {
length < 7 -> "Weak"
containNumbersAmount() < 2 -> "Weak"
containSpecialCharactersAmount() < 2 -> "Weak"
else -> "Strong"
}
}
The problem is that your Lists contain Strings, so every time you call contains on them and pass a Char, it will always be false because a Char is not a String.
Probably, the best way to fix it is to declare Iterables of Chars to check them. Lists are Iterables, but so are ranges.
val password: String = readln()
var numberCount: Int = 0
val numbers: Iterable<Char> = '0'..'9'
var specialCount: Int = 0
val specialCharacters: List<Char> = listOf('!','#','#','$','%','&','*')
And just for your learning, there's a count function that takes a lambda argument that can make this kind of task much easier:
fun main() {
val password: String = readln()
val numbers = '0'..'9'
val specialCharacters = listOf('!','#','#','$','%','&','*')
val numberCount: Int = password.count { numbers.contains(it) }
val specialCount: Int = password.count { specialCharacters.contains(it) }
val result = when {
password.length < 7 || numberCount < 2 || specialCount < 2 -> "Weak"
else -> "Strong"
}
println(result)
}

kotlin equality test of nullable reference of int [duplicate]

This question already has answers here:
Integers caching in Java [duplicate]
(2 answers)
Closed 2 years ago.
I do not understand this snippet of code I found on the official documentation:
fun main() {
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 100000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
}
Why the equality changes when the variable's value change?
The JVM caches Integers for values between -128 and 127. Integers outside that range may or may not be cached - if they aren't, then each call to Integer i = 128 will return a new object.
Kotlin inherits this behaviour (an Int? in kotlin is an Integer in Java).
So, back to your example:
100 gets cached, hence boxedA and anotherBoxedA are the same object
but 100000 is not cached and 2 different instances of Integers are returned

Kotlin boxed Int are not the same

Please help me understand this piece of code in the kotlin docs:-
val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
Now, I understand that first int a = 10000 then in the next line it is comparing it using ===.
Now the question is why when it assigned boxedA=a, it checked if it is null using int?. Can it just be written like this:-
val boxedA: Int=a
Please if I'm understanding it the wrong way, someone guide to check the right place or explain it a bit for me.
First, the Int will be mapped to java int/Integer depending on its context. If Int is a generic argument, then its mapped type is Integer. Otherwise, it is a primitive type int. for example:
val a:Int = 1
//final int a = 1; //mapped to java code
val numbers:List<Int> = asList(1,2,3)
//final List<Integer> numbers = asList(1, 2, 3); //mapped to java code
Secondly, boxing an Int to an Int? is same behavior as java boxing an int to an Integer, for example:
val a:Int = 1 // int a = 1;
val b:Int? = a; // Integer b = a;
Why the boxed Integers are not the same?
This is because Integer only caching values in the range [-128, 127]. the the variable a above is out of the cache range, it will create a new Integer instance for each boxing rather than using a cached value. for example:
// v--- 1 is in cache range
val ranged: Int = 1
val boxedRanged1: Int? = ranged
val boxedRanged2: Int? = ranged
println(boxedRanged1 === boxedRanged2) //true
// v--- 128 is out of cache range
val excluded: Int = 128
val boxedExcluded1: Int? = excluded
val boxedExcluded2: Int? = excluded
println(boxedExcluded1 === boxedExcluded2) //false
when it assigned boxedA = a, it checked if it is null using int?
I have no idea what you mean by this. Making a variable have the type Int? makes it a variable that can either store an Int or null. There is no checking happening at this assignment. If you have a non-null value to assign to the variable, just make it non-nullable, without the ? in the type:
val copyOfA: Int = a
You can even omit the type, and get Int inferred:
val copyOfA = a
As for the comparisons:
== is used for comparing by value in Kotlin (this is the equivalent of using equals in Java), === is used for comparing references (this is == in Java).
When you create boxedA and anotherBoxedA, you create two Integer instances under the hood (because nullable variables can't be represented by primitives). These will be equal when compared with == (they have the same value), but not when compared with === (they are different instances).
You can see the relevant part of the offical docs here.
it checked if it is null using int?
That is not what it means.
Kotlin's null safety feature does not allow a variable to be set as null by default.
Check here.
val anotherBoxedA: Int? = a
This means that anotherBoxedA can be assigned null or is nullable.
val anotherBoxedA: Int? = null
This will be allowed.

Compare String Kotlin

I'm studying kotlin, but I'm very disappointed, I can not compare two Strings.
What is the right way to compare.
btn_login.setOnClickListener {
val login = input_email.text.trim()
val pass = input_password.text.trim()
if( login.equals( pass ) ){
startActivity<MainActivity>()
}
if (login?.equals(other = pass)){
startActivity<MainActivity>()
}
if (login == pass){
startActivity<MainActivity>()
}
}
According to documentation for structual equality use ==. It is translated to a?.equals(b) ?: (b === null).
In you case convert login and pass from SpannableStringBuilder to String.
val login = input_email.text.trim().toString()
Here is the example for matching the two strings using kotlin.
If you are using == (double equals) for matching the string then it's compare the address & return maximum time wrong result as per java documentation so use equals for the same
If you want to use equal ignore case then pass the true in the equals method of String
if (s1.equals(s2,true))
other wise you can just use this without boolean like
if (s1.equals(s2,false)) or if (s1.equals(s2))
compleate code is below
fun main(args: Array<String>) {
val s1 = "abc"
val s2 = "Abc"
if (s1.equals(s2,true))
{
println("Equal")
}
else
{
println("Not Equal")
}
}
Covert both the SpannableStringBuilder to string with toString, this should work.
val login = input_email.text.trim().toString()
val pass = input_password.text.trim().toString()
if (login == pass){
startActivity<MainActivity>()
}
1. == :
if ( string1 == string2 ){...}
2. equals :
Indicates whether some other object is "equal to" this one.
Implementations must fulfil the following requirements:
Reflexive: for any non-null reference value x, x.equals(x) should
return true.
Symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.
Transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true
Consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y) consistently return true or consistently
return false, provided no information used in equals comparisons on
the objects is modified.
/** * Returns `true` if this string is equal to [other], optionally ignoring character case. * * #param ignoreCase `true` to ignore character case when comparing strings. By default `false`. */
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
3. compareTo :
public override fun compareTo(other: String): Int
Compares this object with the specified object for order. Returns zero
if this object is equal to the specified other object, a negative
number if it's less than other, or a positive number if it's greater
than other.
public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
Compares two strings lexicographically, optionally ignoring case
differences
i know this is way too late, but as a newbie learning Kotlin, i had the same doubts.
then i came across this wonderful article that articulates the various string comparison types in Kotlin and the differences between them all.
in short both == and .equals() can be used to compare the value of 2 strings in kotlin.
hopefully that helps
With case checking
String a=.....
String b=.....
if(a==b){
}
IgnoreCase
if(a.equals(b,false))
KOTLIN:
if (editText1.text.toString() == editText2.text.toString() ) {
println("Should work now! The same value")
}
Try the following solution, see if it helps:
val passStr: String = textView.text.toString()
if( loginStr.compareTo(passStr, false) ){
startActivity<MainActivity>()
}
Try this surely will work.
val style = buildString { karthik}
val style2 = buildString { karthik }
var result = style.equals(style2)
if(result){//Do something}

Kotlin referential equality behavior on Int with values between -128 to 127

I'm giving myself until 12:00AM to learn and get productive (hopefully) on kotlin.
Following https://kotlinlang.org/docs/kotlin-docs.pdf I tried these snippets on page 17. Could anyone please help me understand why === returns true if a value is between -128 to 127?
The following indeed prints false:
val a: Int = 10000
val boxedA: Int? = a // Integer#445
val anotherBoxedA: Int? = a // Integer#447 why?
print(boxedA === anotherBoxedA) // false
However changing a to any value between -128 to 127 always prints true:
val a: Int = -128
val boxedA: Int? = a // Integer#445
val anotherBoxedA: Int? = a // Integer#445 why?
print(boxedA === anotherBoxedA) // true!
It seems to me if Int value is outside the bounds of -128 to 127 (Java byte) kotlin creates a new object on assignment does making the reference not equal.
See the Java source code of Integer.valueOf() which is reponsible for boxing int values. The javadoc says:
This method will always cache values in the range -128 to 127
So boxed integers in that range are always the same object if they have the same numeric value.
In Kotlin, you should compare boxed Integers with == and not with ===.