I want to pass a property getter method reference as one of the function arguments, and have that argument be of my own functional interface type, but ran into an issue.
Here's a stripped down minimal reproducible case, I changed the variable from an argument into a property, but the issue is the same.
class Foo {
val bar: Bar? = null
}
class Bar
fun interface FooBarSelector {
fun select(foo: Foo): Bar?
}
class KotlinClass() {
val selector: FooBarSelector = Foo::bar
}
This doesn't compile, Foo::bar is underlined and the error is
Type mismatch.
Required: FooBarSelector
Found: KProperty1<Foo, Bar?>
I tried to look this up, found similar questions about SAM conversions, but they were a bit different and I don't think any of them referred specifically to property getters.
I found that the issue can be solved by doing one of the following:
Remove the explicit type, or replace it with the suggested KProperty1. Not an option, I want to preserve my type.
Replace the method reference with FooBarSelector { it.bar }. Far from ideal, but better than the first option.
Why does this happen and are there any other options? I am new to Kotlin, but not Java.
Kotlin version used is 1.7.20
EDIT:
Here's my original goal: accept a FooBarSelector as an argument, and by default point it at a property getter:
fun doSomething(
selector: FooBarSelector = Foo::bar //doesn't compile
) {
}
Your code with the lambda is fine, but you may prefer this syntax for the same thing:
class KotlinClass() {
val selector = FooBarSelector(Foo::bar)
}
Explanation:
Kotlin function references are more explicit about types than in Java, because function references are a first-class object type. When you want to use a function reference as a functional interface instance, you must convert it. This can be done automatically by the compiler using SAM conversion.
SAM conversion only works when passing a function reference as an argument to a function that has a parameter with a functional interface type. So, it doesn't directly work when assigning to a property.
But Kotlin implicitly provides higher order functions for functional interfaces that allow you to pass a function reference that will convert it into an interface instance. The implicit function is named after the interface, so it looks like a constructor call.
In the above code, the implicit functional interface "constructor" is inline, so there is no intermediate functional object allocated in the compiled code. This compiles to the same thing you would get in Java with a direct method reference.
I am not 100% sure what you are expecting but consider this example:
class Foo(
val bar: Bar
)
data class Bar(
val value: String
)
interface FooBarSelector {
fun select(foo: Foo): Bar {
return foo.bar
}
}
class FooBarCustomSelector: FooBarSelector {
override fun select(foo: Foo): Bar {
return Bar("I don't care about which Foo was passed. I'll return my own Bar")
}
}
class KotlinClass(val selector: (Foo) -> Bar = Foo::bar)
fun main(args: Array<String>) {
val kotlinClassWithDefaultSelector = KotlinClass()
val kotlinClassWithCustomSelector = KotlinClass(FooBarCustomSelector()::select)
val foo = Foo(Bar("Bar1"))
println("kotlinClassWithDefaultSelector: ${kotlinClassWithDefaultSelector.selector(foo)}")
println("kotlinClassWithCustomSelector: ${kotlinClassWithCustomSelector.selector(foo)}")
}
This would print:
kotlinClassWithDefaultSelector: Bar(value=Bar1)
kotlinClassWithCustomSelector: Bar(value=I don't care about which Foo was passed. I'll return my own Bar)
Related
Since Google made Kotlin a first class language for Android, there has been an increase in questions relating to how to perform certain things in Kotlin, "Java-esque" style. The most common ones are how to make static variables in Kotlin. So how do you make Kotlin static variables and functions?
You can't. Well, at least in a pure Kotlin project.
Kotlin has no notion of static. The way static works in a Kotlin-Java project is by use of annotations on the Kotlin classes to tell the JVM that the desired variable/function should be exposed as a static to Java classes.
The following is an example guide for Kotlin-Java static interop (answer originally posted in What is the equivalent of Java static methods in Kotlin?):
Scenario 1: Creating a static method in Kotlin for Java
Kotlin
#file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits
class KotlinClass {
companion object {
//This annotation tells Java classes to treat this method as if it was a static to [KotlinClass]
#JvmStatic
fun foo(): Int = 1
//Without it, you would have to use [KotlinClass.Companion.bar()] to use this method.
fun bar(): Int = 2
}
}
Java
package com.frybits;
class JavaClass {
void someFunction() {
println(KotlinClass.foo()); //Prints "1"
println(KotlinClass.Companion.bar()); //Prints "2". This is the only way to use [bar()] in Java.
println(KotlinClass.Companion.foo()); //To show that [Companion] is still the holder of the function [foo()]
}
//Because I'm way to lazy to keep typing [System.out], but I still want this to be compilable.
void println(Object o) {
System.out.println(o);
}
}
This answer provides more depth than this, and should definitely be referenced for this scenario.
This next scenario handles creating static fields in Kotlin so that Java doesn't have to keep calling KotlinClass.foo() for those cases where you don't want a static function.
Scenario 2: Creating a static variable in Kotlin for Java
Kotlin
#file:JvmName("KotlinClass") //This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits
class KotlinClass {
companion object {
//This annotation tells Kotlin to not generate the getter/setter functions in Java. Instead, this variable should be accessed directly
//Also, this is similar to [#JvmStatic], in which it tells Java to treat this as a static variable to [KotlinClass].
#JvmField
var foo: Int = 1
//If you want something akin to [final static], and the value is a primitive or a String, you can use the keyword [const] instead
//No annotation is needed to make this a field of [KotlinClass]. If the declaration is a non-primitive/non-String, use #JvmField instead
const val dog: Int = 1
//This will be treated as a member of the [Companion] object only. It generates the getter/setters for it.
var bar: Int = 2
//We can still use [#JvmStatic] for 'var' variables, but it generates getter/setters as functions of KotlinClass
//If we use 'val' instead, it only generates a getter function
#JvmStatic
var cat: Int = 9
}
}
Java
package com.frybits;
class JavaClass {
void someFunction() {
//Example using #JvmField
println(KotlinClass.foo); //Prints "1"
KotlinClass.foo = 3;
//Example using 'const val'
println(KotlinClass.dog); //Prints "1". Notice the lack of a getter function
//Example of not using either #JvmField, #JvmStatic, or 'const val'
println(KotlinClass.Companion.getBar()); //Prints "2"
KotlinClass.Companion.setBar(3); //The setter for [bar]
//Example of using #JvmStatic instead of #JvmField
println(KotlinClass.getCat());
KotlinClass.setCat(0);
}
void println(Object o) {
System.out.println(o);
}
}
One of the great features about Kotlin is that you can create top level functions and variables. This makes it greate to create "classless" lists of constant fields and functions, which in turn can be used as static functions/fields in Java.
Scenario 3: Accessing top level fields and functions in Kotlin from Java
Kotlin
//In this example, the file name is "KSample.kt". If this annotation wasn't provided, all functions and fields would have to accessed
//using the name [KSampleKt.foo()] to utilize them in Java. Make life easier for yourself, and name this something more simple
#file:JvmName("KotlinUtils")
package com.frybits
//This can be called from Java as [KotlinUtils.TAG]. This is a final static variable
const val TAG = "You're it!"
//Since this is a top level variable and not part of a companion object, there's no need to annotate this as "static" to access in Java.
//However, this can only be utilized using getter/setter functions
var foo = 1
//This lets us use direct access now
#JvmField
var bar = 2
//Since this is calculated at runtime, it can't be a constant, but it is still a final static variable. Can't use "const" here.
val GENERATED_VAL:Long = "123".toLong()
//Again, no need for #JvmStatic, since this is not part of a companion object
fun doSomethingAwesome() {
println("Everything is awesome!")
}
Java
package com.frybits;
class JavaClass {
void someFunction() {
println(KotlinUtils.TAG); //Example of printing [TAG]
//Example of not using #JvmField.
println(KotlinUtils.getFoo()); //Prints "1"
KotlinUtils.setFoo(3);
//Example using #JvmField
println(KotlinUtils.bar); //Prints "2". Notice the lack of a getter function
KotlinUtils.bar = 3;
//Since this is a top level variable, no need for annotations to use this
//But it looks awkward without the #JvmField
println(KotlinUtils.getGENERATED_VAL());
//This is how accessing a top level function looks like
KotlinUtils.doSomethingAwesome();
}
void println(Object o) {
System.out.println(o);
}
}
Another notable mention that can be used in Java as "static" fields are Kotlin object classes. These are zero parameter singleton classes that are instantiated lazily on first use. More information about them can be found here: https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations
However, to access the singleton, a special INSTANCE object is created, which is just as cumbersome to deal with as Companion is. Here's how to use annotations to give it that clean static feel in Java:
Scenario 4: Using object classes
Kotlin
// There is no more need for the #file:JvmName() annotation. The object class below already handles the proper naming.
//This provides a name for this file, so it's not defaulted as [KotlinClassKt] in Java
package com.frybits
object KotlinClass { //No need for the 'class' keyword here.
//Direct access to this variable
const val foo: Int = 1
//Tells Java this can be accessed directly from [KotlinClass]
#JvmStatic
var cat: Int = 9
//Just a function that returns the class name
#JvmStatic
fun getCustomClassName(): String = this::class.java.simpleName + "boo!"
//Getter/Setter access to this variable, but isn't accessible directly from [KotlinClass]
var bar: Int = 2
fun someOtherFunction() = "What is 'INSTANCE'?"
}
Java
package com.frybits;
class JavaClass {
void someFunction() {
println(KotlinClass.foo); //Direct read of [foo] in [KotlinClass] singleton
println(KotlinClass.getCat()); //Getter of [cat]
KotlinClass.setCat(0); //Setter of [cat]
println(KotlinClass.getCustomClassName()); //Example of using a function of this 'object' class
println(KotlinClass.INSTANCE.getBar()); //This is what the singleton would look like without using annotations
KotlinClass.INSTANCE.setBar(23);
println(KotlinClass.INSTANCE.someOtherFunction()); //Accessing a function in the object class without using annotations
}
void println(Object o) {
System.out.println(o);
}
}
Is there any type in Kotlin language that I could use in a late initialization instead of java.lang.Integer so that I do not get a compiler warning?
Let's say I have a class like this one:
class SomeClass {
#Value(#{config['poolCapacity']?:'5000'})
lateinit var somePool: Integer
}
I can't use Int type from Kotlin because it's primitive type and lazeint does not accept it.
If I stick to java.lang.Integer it works just fine but I am getting compiler warning of this sort:
SomeClass.kt: (20, 24): This class shouldn't be used in Kotlin. Use
kotlin.Int instead.
Obviously I might create needed type myself but I simply wonder if there is something out of the box and recommended that we should use in such situation and I simply can't find it? (Annotated constructor is not a solution in this particular case).
The simplest solution is don't to use a late-initialized property since Kotlin late-initialized property don't support for primitive types now, and you can initialize it with the default value of spring expression, for example:
#Value(#{config['poolCapacity']?:'5000'})
var somePool: Int = 5000
A complex example you can write a delegated properties, but you must annotated at setter by #set site-target rather than field/property , for example:
#set:Value(#{config['poolCapacity']?:'5000'})
var value by required<Int>()
inline fun <reified T> required(): ReadWriteProperty<Any, T> {
return object : ReadWriteProperty<Any, T> {
var value: T? = null;
override fun getValue(thisRef: Any, property: KProperty<*>): T = value as T
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.value = value;
}
}
}
1) In Java, I can do this:
Void z = null;
Is there any other value except null I can assign to z?
2) Consider the following code snipped:
Callable<Void> v = () -> {
System.out.println("zzz");
Thread.sleep(1000);
return null;
};
This compiles OK, but if I remove the last statement return null; it doesn't. Why? After all, Void is supposed to mean no return value.
From the docs:
The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.
So, no.
Void is used by methods having to return an object, but really returning nothing.
A decent example can be observed with some usage of the AsyncTask in Android, in cases where you don't need to return any object after the task is complete.
You would then extend AsyncTask<[your params type], [your progress type], Void>, and return null in your onPostExecute override.
You wouldn't need it in most cases though (for instance, Runnable is typically more suitable than Callable<Void>).
Ansering your question more specifically:
But if I remove the return null it does not compile?! Why?
... because a Void is still an object. However, it can only have value null.
If your method declares it returns Void, you need to (explicitly) return null.
If you check the sources:
package java.lang;
public final class Void {
public static final Class<Void> TYPE = Class.getPrimitiveClass("void");
private Void() {
}
}
Void is:
final class;
has private constructor.
Without using Reflection it's not possible to assign anything but null to a reference of Void type.
In Java, I can do this Void z = null; Is there any other value (but null) which I can assign to z ?
You can if you create you own Void instances. You can use Reflection or Unsafe to create these, not that it's a good idea.
But if I remove the return null it does not compile?! Why? After all, Void is supposed to mean just that - no return type.
Java is case sensitive, this means that Boolean and boolean are NOT the same type nor is Void and void. Void is a notional wrapper for void but otherwise is just a class you shouldn't create any instance of.
Maybe what you are asking for is Runnable or Consumer - some interface that doesn't have a return value. Void only serves to show that you cannot expect anything else than null. It is still just a class, not a keyword or anything special. A class that cannot be instantiated, so you have to return null.
A lot of efforts were spent in designing lambda expression to treat int/Integer etc indistinguishably, so that int->Long will be compatible with Integer->long, etc.
It is possible (and desirable) to treat void/Void in a similar way, see comments from Goetz and Forax.
However, they didn't have the time to implement the idea for java8 :(
You can introduce an adapter type that is both ()->void and ()->Void; it can simplify your use case a little bit, see http://bayou.io/release/0.9/javadoc/bayou/util/function/Callable_Void.html
If you have a method that accepts ()->Void, it is not going to work well with ()->void lambdas. One workaround is to overload the method to accept ()->void. For example, ExecutorService
submit(Callable<T> task)
submit(Runnable task)
...
submit( System::gc ); // ()->void
However, overloading with functional parameter types is tricky... The example above works because both accept a zero-arg function. If the function has non-zero args
foo( Function<String,Void> f ) // String->Void
foo( Consumer<String> f ) // String->void
it's confusing to the compiler (and the programmer)
foo( str->System.out.println(str) ); // which foo?
foo( System.out::println ); // which foo?
Given an implicit lambda str->expr, the compiler needs a target type to make sense of it. The target type here is given by the method parameter type. If the method is overloaded, we need to resolve method overloading first... which typically depends on the type of the argument (the lambda)... So you can see why it is complicated.
(A zero-arg lambda is never implicit. All argument types are known, since there's no argument.)
The lambda spec does have provisions to resolve the following cases
foo( str->{ System.out.println(str); } );
foo( str->{ System.out.println(str); return null; } );
You may argue that in the previous example,
foo( str->System.out.println(str) );
since println(str) returns void, the Void version obviously does not fit, therefore the compiler should be able to resolve it. However, remember that, to know the meaning of println(str), first, the type of str must be resolved, i.e. method overloading of foo must be resolved first...
Although in this case, str is unambiguously String. Unfortunately, the lambda designer decided against to be able to resolve that, arguing it is too complicated. This is a serious flaw, and it is why we cannot overload methods like in Comparator
comparing( T->U )
//comparing( T->int ) // overloading won't work well
comparingInt ( T->int ) // use a diff method name instead
Suppose I have
val a: Option[String] = None
someJavaFunction(a)
And then in the java file, I want to do something like this:
public someJavaFunction(Option<String> o) {
o.orNull();
}
The signature of orNull, however, is this:
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
So from Java, I'd need to supply this evidence function that is usually magicked in by Scala (from I know not where). How might I get hold of the evidence value to pass in here?
This is clearly not sensible.
Is it possible?
The <:< class is defined in scala.Predef and normally it's scala.Predef.conforms() that gives you an instance in Scala. So you could do something like
public class Foo {
public static String foo(scala.Option<String> o) {
return o.orNull(
(scala.Predef.$less$colon$less< scala.runtime.Null$ , String >)
(Object)scala.Predef.conforms()
);
}
}
which gives an unchecked operation warning, but works.
You can also create an instance of scala.Predef.$less$colon$less that does the right thing (just returns its argument), and there the cast goes through without warning.
Note: you must leave a space after Null$ or javac gets confused.
In Java we can resolve a variable's class through getClass() like something.getClass(). In Kotlin I am aware of something.javaClass which is nice but I want to be able to get the KClass in a similar way. I've seen the Something::class syntax but this is not what I need. I need to get the KClass of a variable. Does such functionality exist?
The easiest way to achieve this since Kotlin 1.1 is the class reference syntax:
something::class
If you use Kotlin 1.0, you can convert the obtained Java class to a KClass instance by calling the .kotlin extension property:
something.javaClass.kotlin
EDIT: See comments, below, and answer from Alexander, above. This advice was originally for Kotlin 1.0 and it seems is now obsolete.
Since the language doesn't support a direct way to get this yet, consider defining an extension method for now.
fun<T: Any> T.getClass(): KClass<T> {
return javaClass.kotlin
}
val test = 0
println("Kotlin type: ${test.getClass()}")
Or, if you prefer a property:
val<T: Any> T.kClass: KClass<T>
get() = javaClass.kotlin
val test = 0
println("Kotlin type: ${test.kClass}")
Here's my solution
val TAG = javaClass.simpleName
With javaClass.simpleName you can obtain your class name. Also the above example is very useful for android developers to declare on top of the class as an instance variable for logging purposes.
Here are different Implementations to get class names. You can utilize it as per your requirements.
import kotlin.reflect.KClass
val <T : Any > T.kClassName: KClass<out T>
get() {
return javaClass.kotlin
}
Here we can get the class name in kotlin
val <T : Any > T.classNameKotlin: String?
get() {
return javaClass.kotlin.simpleName
}
Here we can get the class name in kotlin
val <T : Any > T.classNameJava: String
get() {
return javaClass.simpleName
}
Here are the outputs to the following operations.
fun main(){
val userAge = 0
println(userAge.kClassName)
Output: class java.lang.Integer (Kotlin reflection is not available)
println(userAge.classNameKotlin)
Output: Int
println(userAge.classNameJava)
Output: Integer
}
Since Kotlin 1.5.21 (org.jetbrains.kotlin:kotlin-stdlib:1.5.21)
val TAG = javaClass.simpleName will work no more!
Error "Not enough information to infer type variable T"
/**
* Returns the runtime Java class of this object.
*/
public inline val <T : Any> T.javaClass: Class<T>
#Suppress("UsePropertyAccessSyntax")
get() = (this as java.lang.Object).getClass() as Class<T>
#Deprecated("Use 'java' property to get Java class corresponding to this Kotlin class or cast this instance to Any if you really want to get the runtime Java class of this implementation of KClass.", ReplaceWith("(this as Any).javaClass"), level = DeprecationLevel.ERROR)
public inline val <T : Any> KClass<T>.javaClass: Class<KClass<T>>
#JvmName("getRuntimeClassOfKClassInstance")
#Suppress("UsePropertyAccessSyntax")
get() = (this as java.lang.Object).getClass() as Class<KClass<T>>
You can try now
YourClassName::class.java.simpleName
In Kotlin:
val className = serviceClass.javaClass.name
I think this is the better solution.
Found here https://www.techiedelight.com/determine-class-name-in-kotlin/
fun main() {
val s = "Kotlin"
println(s::class) // class kotlin.String
println(s::class.qualifiedName) // kotlin.String
println(s::class.simpleName) // String
}