interface difference in Java and Kotlin

ahmed shaaban
8 min readOct 11, 2020

--

1- what is Interface and its property?
2- why an interface can’t store the state?
3- How to Implement interface property in Concrete type?
4- what happens if the class implements multiple interfaces and both the interfaces have the same functions?
5- interface difference in Java and Kotlin
6- Functional interfaces(SAM Single Abstract Method)
7- Use a lambda in place of a functional interface?
8- Why use Object Expressions to instiate anonymous interface?
9- Functional interfaces vs. type aliases?
10- why can’t use Generic inside Interface Declaration?
11- default function implementation of interface?

what are Interface and its property?

Interfaces are custom types provided by Kotlin that cannot be instantiated directly. Instead, these define a form of behavior (like contracts) that the implementing types have to follow. With the interface, you can define a set of properties and methods, that is used by classes for specific behaviors.

Interfaces in Kotlin contain

  • declarations of abstract methods and method implementations
  • abstract properties
  • properties that provide accessor implementations but can’t store the state
  • can’t have any constructor.

- A class can implement multiple interfaces too using the above concept.

- We need to implement all the abstract properties of the interface or else set the class as an abstract class.

- Interfaces are useless unless they’re implemented by a class.

why an interface can’t store the state?

  • We cannot use the backing field from Properties in interfaces since an interface doesn’t store any state and hence no previous values.

How to Implement property in Concrete type implemented Interface?

interface MyInterface{ 
fun print(){
println("This is a default method defined in the interface")
}
var value1: String
get() = "You Name"
set(value) {}
}
  1. An override modifier overrides the property from the interface defined.
class MyClass() : MyInterface{
override var value1: String = "Ahmed Shaaban"
}

2. Overriding properties inside the constructor

class MyClass(override var value1: String) : MyInterface{ 
}

what happens if the class implements multiple interfaces and both the interfaces have the same functions?

  • we override the function implementation in our class, our class would have a single common overridden implementation

Resolving overriding conflicts

  • if we need to access the function from the interface?
    using super<MyInterface> if you use only super would give a compile-time error since the compiler doesn’t know which of the interfaces to go to.

interface difference in Java and Kotlin

  • In Kotlin, unlike Java, static members of interfaces are not derived and cannot be called in subclasses without qualifying the interface name. This seems to be different for classes: the non-qualified name of a base class static member resolves to it, but the member is still not inherited.
  • you can use lambda in Java’s SAM param for short and cleaner code, but not Kotlin’s SAM, function type is the first class in Kotlin, so, SAM has no meaning for Kotlin, function type with type alias is more Kotlin style. so people define the interface in Java, and you’ll be able to use lambdas in both languages with no problem.

Functional interfaces(SAM Single Abstract Method)

  • An interface with only one abstract method is called a functional interface.
  • The functional interface can have several non-abstract members but only one abstract member.
fun interface EvenNumberCheck {
fun checkEvenNumber(i: Int): Boolean
}

Without SAM Conversion

// Creating an instance of a class
val isEven = object : EvenNumberCheck{
override fun checkEvenNumber(i: Int): Boolean {
return i % 2 == 0
}
}

With SAM Conversion (Creating an instance using lambda)

val isEven = EvenNumberCheck{ it % 2 == 0 }

Kotlin can convert any lambda expression whose signature matches the signature of the interface’s single method into an instance of a class that implements the interface.

Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be automatically converted into implementations of Java interfaces with a single non-default method, as long as the parameter types of the interface method match the parameter types of the Kotlin function.

Before Kotlin 1.4.0, you could apply SAM (Single Abstract Method) conversions only when working with Java methods and Java interfaces from Kotlin. From now on, you can use SAM conversions for Kotlin interfaces as well. To do so, mark a Kotlin interface explicitly as functional with the fun modifier.

SAM conversion applies if you pass a lambda as an argument when an interface with only one single abstract method is expected as a parameter. In this case, the compiler automatically converts the lambda to an instance of the class that implements the abstract member function.

fun interface MyInterface
{
fun onLocationMeasured(location: String)
}

fun main()
{
val myObj = MyInterface { println(it) }

myObj.onLocationMeasured("New York")
}

Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have just a single abstract method.

Use a lambda in place of a functional interface?

when use lambda:-

If your last argument is a function, you can just forget about ‘()’, and pass lambda. use lambda in SAM param for shortening and cleaner

public fun setItemListener(param: Int, myListener: (View) -> Unit)

to call the method above, your code should be:

item.setItemListener(0) { /* lambda here */ }

Solution:-
1. use type alias
typealias EventHandler<T> = (T) -> Unit

Register it like this:

val myObject = { location -> ...}
addLocationHandler(myObject)

Another Example:-

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {}

2. use a factory method: You can define a function named EventHandler:

fun <T> EventHandler(handler: (T) -> Unit): EventHandler<T> 
= object : EventHandler<T> {
override fun handle(event: T) = handler(event)
}

Another way make listener a function

var listener: (() -> Unit)? = null
fun setOnBackPressed(l: () -> Unit) {
listener = l
}

then invoke it by:

listener?.invoke()

3. It works if the companion object implements the invoke function taking a lambda.

Kotlin interface

interface Foo{
fun bar(input: String): String
companion object {
inline operator fun invoke(crossinline function:
(String) -> String) = object : Foo{
override fun bar(input: String) =function(input)
}
}
}

Kotlin implementation

fun createFoo()= Foo { input: String -> "Hello $input!" }

4. for Kotlin 1.4+. It can use SAM-conversion for Kotlin functions if you mark an interface as a “functional” interface:

fun interface Listener {
fun onEvent()
}

The problem is when you have an interface with more than one method because then you cannot pass a lambda

When converting our libraries to Kotlin, we actually left all the interfaces in Java code, as it was cleaner to call Java from Kotlin than Kotlin from Kotlin.

instantiate Interface In Kotlin

// Use Kotlin's SAM conversion
webView.evaluateJavascript("a") {
println(it) // "it" is the implicit argument passed in to function
}
// Use Kotlin's SAM conversion with explicit variable name
webView.evaluateJavascript("a") { value ->
println(value)
}
// Specify SAM conversion explicitly
webView.evalueateJavascript("a", ValueCallback<String>() {
println(it)
})
// Use an anonymous class
webView.evalueateJavascript("a", object : ValueCallback<String>() {
override fun onReceiveValue(value: String) {
println(value)
}
})

Why use Object Expressions ??

  • we need to create an object of a slight modification of some class, without explicitly declaring a new subclass for it.
  • To create an object of an anonymous class that inherits from some type (or types).

can we use a listener without some interface and with a default value?

val someButtonListener: (isChecked: Boolean) -> Unit = {_ -> }
val someButtonListener: (v: View) -> Unit = {_ -> }

Functional interfaces vs. type aliases

typealias EventHandler<T> = (T) -> Unitinterface EventHandler<T> {

fun handle(event: T)

}
  • Type aliases are just names for existing types — they don’t create a new type, while functional interfaces do.
  • Type aliases can have only one member, functional interfaces can have multiple non-abstract members and one abstract member.
  • Functional interfaces can also implement and extend other interfaces.
  • functional interfaces are more flexible and provide more capabilities than type aliases.

why can’t use Generic inside Interface Declaration?

because must has Constructor

interface MyInterface<T> {
// Must have constructor (t: T)
public void onReceiveValue(T value);
}

use an abstract class or a plain class:

abstract class MyContractClass<T>(val t: T)class ContractImp<T>(t: T): MyContractClass<T>(t)

Use a lambda in place of a functional interface?

@FunctionalInterface
interface EventHandler<T> {
fun handle(event: T)
}

When converting our libraries to Kotlin, we actually left all the interfaces in Java code, as it was cleaner to call Java from Kotlin than Kotlin from Kotlin.

The 3 current options seem to be:

  • typealias (messy when called from java)
  • kotlin interface (messy when called from kotlin; you need to create an object) This is a big step back IMO.
  • java interface (less messy when called from kotlin; lambda needs interface name prepended so you don’t need an object; also can’t use lambda outside of function parenthesis convention)

Possible solutions:

  1. Define the interface in Java. Useful if it is a library/code that may be used from a Java code.
  2. Make the method receive a function as an argument:
// Example listener receives a bool and return unit.   fun setMyListener(listener: (isChecked: Bool) -> Unit) { ... }   ّ
// Usage: obj.setMyListener { isChecked -> }

3. Use type alias (only supported in Kotlin 1.1+):

typealias MyListener = (Bool) -> Unit fun setMyListener(listener: MyListener) { ... }

how I could change the click listener or build-in function that takes interface as a parameter ?

wrap them in inline function + crossinline just restricts to use of “return” in inlined lambda because it can finish the wrong function

inline fun backPress(crossinline action:()-> Unit ):  
OnBackPressedListener {
return object: OnBackPressedListener {
override fun onBackPressed() {
action()
}
}
}

And then just set listener

activity.setOnBackPressed(backPress {  
/* Do something */
})

default function implementation of the interface

  • Kotlin Interface supports default implementation. This implies that we can have a default implementation to all the properties and functions defined in the Interface.

Solution(1)
You need to annotate the methods with the @JvmDefault annotation: JVM-level default interface methods were introduced with Java 1.8. This causes Kotlin to use a different approach to compile default interface methods than Java does.

interface Foo {
@JvmDefault
fun bar(): String {
return "baz"
}
}

problem => This feature is still disabled by default, you need to pass the
-Xjvm-default=enable flag to the compiler for it to work.

Solution(2) => extension functions

If you know you won’t be overriding the function in any implementations of your interface, you can use extension functions as a nice workaround for this issue. Just put an extension function in the same file as the interface (and at the top level so other files can use it).

interface MyInterface{
// presumably other stuff
}
fun MyInterface.show(): String {
return "Ahmed Shaaban"
}

extension functions don’t do what you might expect from regular polymorphism. What this means for this workaround is that the default function cannot be overridden like a regular function. If you try to override it, you’ll get some weird behavior, because the “overridden” version will be called whenever you’re dealing explicitly with the subclass, but the extension version will be called when you’re dealing with the interface generically.

interface MyInterface {
fun a()
}
fun MyInterface.b() {
println("MyInterface.b() default implementation")
}
class MyInterfaceImpl : MyInterface {
override fun a() {
println("MyInterfaceImpl.a()")
}
fun b() {
println("MyInterfaceImpl.b() overridden implementation")
}
}
fun main(args: Array<String>) {
val inst1: MyInterface = MyInterfaceImpl()
inst1.a()
inst1.b() // calls the "default" implementation
val inst2: MyInterfaceImpl = MyInterfaceImpl()
inst2.a()
inst2.b() // calls the "overridden" implementation
}

Generating true default methods callable from Java You need to annotate the methods with the @JvmDefault annotation:

interface Foo {
@JvmDefault
fun bar(): String {
return "baz"
}
}

This feature is still disabled by default, you need to pass the -Xjvm-default=enable flag to the compiler for it to work.

--

--