What I don't like when using interface of a function with default arguments in Kotlin from Java

I think it's common to define a function with default arguments in Kotlin and use it, but when I tried to use it from Java, I felt a little unpleasant. I'd like to know the best way, but I couldn't find it, so I'll leave it in the hope that someone will tell me.

The implementation contents of the interface are appropriate because they are verification codes.

Define a connect function that manages the connection to the database with a loan pattern.

ConnectionManager


interface ConnectionManager {

  fun createConnection(host: String): Connection {
    return Connection(host)
  }
  
  fun<A> connect(c: Connection = createConnection("localhost"), f: (Connection) -> A): A {
    try {
      c.begin()
      return f(c)
    } catch (e: Exception) {
      c.rollback()
      throw e
    } finally {
      c.commit()
    }
  }
}

Image that connects to the database, issues a select statement, and returns a User instance

UserDao


class UserDao : ConnectionManager {
  fun findById(id: Int): User {
    return connect { c -> c.select("select * from user where id = ${id}", User()) }
  }
}

There is no particular problem so far. So, I had a problem when I wanted to use this interface from Java as well.

UserDaoJava


public class UserDaoJava implements ConnectionManager {
  public User findById(int id) {
    return connect(c -> c.select("select * from user where id = " + id, new User()) );
  }
}

This will result in a compilation error. From Java, arguments that omit the default arguments cannot be called as one connect function.

I couldn't help it, so I added a function with one argument to the interface.

ConnectionManager


interface ConnectionManager {

···abridgement···
  
  //Add this function unavoidably
  fun<A> connect(f: (Connection) -> A): A {
    return connect(createConnection("localhost"), f)
  }
}

I wonder if this is okay, but it still doesn't compile. From Java, the default implementation of Kotlin's interface cannot be called as is. Therefore, it must be overridden on the Java class side to be used.

UserDaoJava


public class UserDaoJava implements ConnectionManager {

···abridgement···
  
  //I need the bottom three
  @NotNull
  @Override
  public Connection createConnection(@NotNull String host) {
    //I want to use the internal implementation of ConnectionManager, so I call it as it is.
    return ConnectionManager.DefaultImpls.createConnection(this, host);
  }

  @Override
  public <A> A connect(@NotNull Connection c, @NotNull Function1<? super Connection, ? extends A> f) {
    return ConnectionManager.DefaultImpls.connect(this, c, f);
  }

  @Override
  public <A> A connect(@NotNull Function1<? super Connection, ? extends A> f) {
    return ConnectionManager.DefaultImpls.connect(this, f);
  }
}

Now the compilation works as well. However, I don't like seeing two connect functions when using ConnectionManager on Kotlin side, and above all, I can't override it every time I use it on Java side.

So let's create a ConnectionManager for Java !!

First, delete the connect function with one argument added earlier from ConnectionManager. Then, define the connect function with one argument in the newly created ConnectionManager for Java.

ConnectionManagerJava


public interface ConnectionManagerJava extends ConnectionManager {
  @NotNull
  @Override
  default Connection createConnection(@NotNull String host) {
    return ConnectionManager.DefaultImpls.createConnection(this, host);
  }

  @Override
  default <A> A connect(@NotNull Connection c, @NotNull Function1<? super Connection, ? extends A> f) {
    return ConnectionManager.DefaultImpls.connect(this, c, f);
  }

  default <A> A connect(@NotNull Function1<? super Connection, ? extends A> f) {
    return connect(createConnection("localhost"), f);
  }
}

And UserDaoJava changed to use ConnectionManagerJava

UserDaoJava


public class UserDaoJava implements ConnectionManagerJava {
  public User findById(int id) {
    return connect(c -> c.select("select * from user where id = " + id, new User()) );
  }
}

Now you can remove the one-argument connect function you added to Kotlin's ConnectionManager, and the Java side is clean. However, since the interface uses the default implementation, there is a problem that it must be Java 8.

With this kind of feeling, I came up with the trick of creating an interface on the Java side in order to use the interface with Kotlin's default arguments from Java, but I feel that something is wrong. .. ..

I'm wondering if this is the correct answer, if it's different from what Kotlin's interface implements, or if there's a different way.

Recommended Posts

What I don't like when using interface of a function with default arguments in Kotlin from Java
What I learned when building a server in Java
I want to make a function with kotlin and java!
Implementation of like function in Java
[Note] What I learned in half a year from inexperienced (Java)
[Note] What I learned in half a year from inexperienced (Java) (1)
[Note] What I learned in half a year from inexperienced (Java) (3)
What I thought about when I started migrating from Java to Kotlin
How to use the function implemented in Kotlin Interface introduced in Maven as the default implementation from Java 8
A note of what I stumbled upon and noticed in catching up with Laravel from Rails
[Rails] What I learned from a little stumbling block when using ancestry
I wrote a Lambda function in Java and deployed it with SAM
Summary of points I was worried about when migrating from java to kotlin
What I did when I converted java to Kotlin
Call a method with a Kotlin callback block from Java
I tried to make a login function in Java
Summary of how to implement default arguments in Java
A summary of what Java programmers find when reading Kotlin source for the first time
I want to make a list with kotlin and java!
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I tried to make a client of RESAS-API in Java
I wrote a C parser (like) using PEG in Ruby
Find the number of days in a month with Kotlin
[Rails] Implementation of multi-layer category function using ancestry "I tried to make a window with Bootstrap 3"
When I was worried about static methods in java interface, I arrived in the order of name interpretation
[Java] Precautions when creating a process that calls a method of Abstract class using DI from a child class
When installing a gem with C extension in Ruby, I want to finish it quickly using multiple CPU cores like make -j4
I made a command line interface with WinMerge Plugin using JD-Core
I can't log in to MySQL from Django when using docker-compose
Sample of using Salesforce's Bulk API from Java client with PK-chunking
I tried to implement Ajax processing of like function in Rails
I can't create a Java class with a specific name in IntelliJ
Let's create a TODO application in Java 6 Implementation of search function
About what I did when creating a .clj file in Clojure
Let's create a TODO application in Java 8 Implementation of editing function
I wrote a Stalin sort that feels like a mess in Java
What I learned from doing Java work with Visual Studio Code
What I often do when I have trouble naming with Java (etc.)
I created a PDF in Java.
What I learned with Java Gold
I tried using JWT in Java
What I learned with Java Silver
I tried using GoogleHttpClient of Java
The story of making a game launcher with automatic loading function [Java]
Even in Java, I want to output true with a == 1 && a == 2 && a == 3 (PowerMockito edition)
I tried to make a talk application in Java using AI "A3RT"
I want to ForEach an array with a Lambda expression in Java
[Java] Get MimeType from the contents of the file with Apathce Tika [Kotlin]
An error occurred when executing a function from MyBatis with the OUT parameter set to CURSOR in PostgreSQL.