Calling Kotlin from Java – Interoperability

Things to consider when calling Kotlin from Java.

import academy.learnprogramming.kotlincode.*;

import static academy.learnprogramming.kotlincode.CarKt.topLevel;
import static academy.learnprogramming.kotlincode.StaticCar.anotherTopLevel;

public class Main {

    public static void main(String[] args) {
  // So how do we call the top-level function from the Car.kt file?
        topLevel(); // If we type the function name the IDE suggests an import (see above). Compiler will quietly generate static class for all top-level items and will give the class the same name as the Kotlin file name.
        // So if we want to refer to a class we use the file name:
        CarKt.topLevel();
        //To demonstrate how we can deal with naming conflicts:
//        anotherTopLevel(); // Without using JvmName to rename file IDE cannot locate this function
        anotherTopLevel(); //Once JvmName has been implemented the IDE will suggest an import under the 'StaticCar' file name
        CarKt.print("Print this Java string"); // We cannot invoke extension function like we would in Kotlin. Need to use standard call
        Car car = new Car("blue", "BMW", 2011);
        System.out.println(car.getModel()); // We call getters and setters from Java as standard as compiler has produced these for Kotlin class properties by default (val only generates getters). Wouldn't work if properties private
        Car2 car2 = new Car2("red", "Ferrari", 2017, false);
        car2.setColour("purple"); // If custom sets and gets are created Java will access those
//        car2.setModel("A3"); // But not if setter is private
//        car2.setYear(1999); // Doesn't exist as setters only generated for var not val
        System.out.println(car2.getColour());
        System.out.println(car2.isAutomatic()); // When dealing with Booleans generates getter name beginning with 'is'
        // If we want Java to access the property directly without going through getter or setter, we can add an @JvmField annotation to the property:
        int year = car2.year; // Can't use @JvmField with private properties or one that overrides another property or can be overridden, or one with const keyword
        // How do we access functions within companion objects? Same for non-anonymous object instances (instances we create using the object keyword)?
        // Must use @JvmStatic annotation. Results in two version being created. One in instance as normal, but also one as a Java static function.
        Car2.Companion.carComp(); // Without @JvmStatic we're accessing the instance method generated by the compiler, not the static version. So we can't type Car2.carComp()
        Car2.carComp2(); // With the @JvmStatic annotation. Means we're accessing the static version of the method.
        // This could be necessary if carComp() was accessing static properties
        // For named object instances i.e. Singletons:
        SingletonObj.INSTANCE.doSomething(); // We can go through the INSTANCE object to access the functions within. Compiler creates an instance and assigns INSTANCE to it
        SingletonObj2.doSomething2(); // If we annotate the function with @JvmStatic we can access it directly
        // Fields, if they're not private:
        System.out.println("is 4WD = " + Car2.Companion.is4WD()); // Without @JvmField
        System.out.println("is pimped out = " + Car2.isPimpedOut); // With @JvmField
        // If the field is a const you don't need to annotate it - automatically converted to static field:
        System.out.println("a constant = " + Car2.constant);
        // Also true for late initialised properties (whatever they are)

        // Null safety
        // Nothing stopping Java passing a null object to a nonNullable function parameter - Kotlin will generate an exception:
//        car2.printMe(null);
        // Kotlin doesn't require functions to declare what exceptions they can throw, whereas Java does.  What happens when we call an exception-able Kotlin function from Java?
//        CarKt.doIO(); // Throws IOException. Can we catch it?
//        try {
//            CarKt.doIO();
//        } catch (IOException e) { // Error - 'IOException is never thrown' - Java can't see the potential exception
//
//        }
        try {
            CarKt.doIO2();
        } catch (IOException e) { // @Throws annotation solves the problem
            System.out.println("IOException!");
        }
        // What happens when we've defined default parameters in a Kotlin function?
        CarKt.defaultArgs("The number is: ", 40);
//        CarKt.defaultArgs("The number is: "); // Error even though second argument should be optional
        // When a Kotlin function with default values is called, only one version is generated for Java (requires all parameters). Annotate with @JvmOverloads:
        CarKt.defaultArgs2("The number is: "); // All better
    }
}

 

fun topLevel() = println("I'm in the car file")

fun main() {
    "Print this".print() // Calling the extension function from within the Kotlin class, as standard
}

object SingletonObj {
    fun doSomething() = println("I'm doing something in the Singleton object")
}

object SingletonObj2 {
    @JvmStatic fun doSomething2() = println("I'm doing something in the second Singleton object")
}

fun doIO() {
    throw IOException()
}

@Throws(IOException::class)
fun doIO2() {
    throw IOException()
}

fun defaultArgs(str: String, num: Int = 25) {}

@JvmOverloads fun defaultArgs2(str: String, num: Int = 25) {}

class Car(val colour: String, var model: String, val year: Int) {

}

class Car2(colour: String, model: String, @JvmField val year: Int, val isAutomatic: Boolean) { // year property has been designated for direct access through Java

    companion object {
        const val constant = 25
        val is4WD = false
        @JvmField val isPimpedOut = true
        fun carComp() = println("I'm in car's companion object")
        @JvmStatic fun carComp2() = println("I'm also in car's companion object")
    }

    fun printMe(text: String) {
        println("I don't expect a null value: $text")
    }

    var colour: String = colour
    set(value) { // example custom setter which always produces same output
        field = "always green"
    }
    var model: String = model
    private set(value) {
        field = "Focus"
    }
}

fun String.print() { // Extension function
    println(this)
}

 

Calling Java from Kotlin – Interoperability

Things to consider when calling Java from Kotlin.

fun main() {
    val car = Car("silver", "Audi", "A3", "3.2 V6", "Leather", 2004)
    car.colour = "Akoya silver" // Can only refer to this like a property if getter and setters are set in Java. Will work without setter if property is public, but not usually desirable
    // Wildcard assignments in Java are converted to use-site variance in Kotlin. ? extends someClass -> out someClass, ? super someClass -> in someClass
    // If you call a Java method that throws an exception and you don't handle the exception in the code, you don't have to declare that the Kotlin function throws the exception - Kotlin doesn't care
    // varargs: If you want to call a Java method that wants multiple arguments:
    car.variableMethod(5, "hello", "goodbye") // This works
    val strings = arrayOf("hello", "goodbye")
//    car.variableMethod(10, strings) // But it doesn't allow us to pass in an array
    car.variableMethod(10, *strings) // So we need to use the spread operator to unpack the array
    // Kotlin doesn't have void, so it will return Unit
    // As previously discussed, when Java method expects primitive types we cannot use arrayOf. We need to use e.g. intArrayOf or call .toIntArray on the array:
//    car.wantsIntArray(arrayOf(1, 2, 3)) // Nope
    car.wantsIntArray(intArrayOf(1, 2, 3)) // Fine
    car.wantsIntArray(arrayOf(1, 2, 3).toIntArray()) // Fine
    // Any? is top of Kotlin hierarchy, Object is top of Java. What happens when Java calls Object explicitly? Will be treated like Any in Kotlin.
    // However, does not have methods such as wait(), notify(), clone() or finalize(). If wanting to call these cast the variable to java.lang.Object in your Kotlin code:
//    car.anObject.equals("bh") // Has equals() method and some others but missing the methods listed above
//    (car.anObject as java.lang.Object).notify() // All methods now available on casting
    // Static methods and fields are translated to companion objects. You can't pass the companion object around as a value but you can use its members
    println("x = ${Car.x}") // Accessing static variable
    println(Car.xString()) // The same as calling a companion object
    // Single Abstract Method (SAM) interface as of Java 8, can use lambda. E.g. Runnable interface is a SAM (see Car.java demoMethod and demoMethod2)
    // If a Java method wants an object that implements a SAM interface e.g. Runnable then you can pass it a Kotlin function:
    car.demoMethod3 ({ println("I'm in a Thread") }) // Function signature has to match parameter, in this case Runnable
}
package academy.learnprogamming.javainteroperability;


import org.jetbrains.annotations.NotNull; // N.B. Had to prompt for download from Maven
import org.jetbrains.annotations.Nullable;

public class Car {

    public static int x = 5;

    private String colour;
    private String manufacturer;
    private String model;
    private String variant;
    private String interior;
    private int year;
    private Object anObject;

    public Car(String colour, String manufacturer, String model, String variant, String interior, int year) {
        this.colour = colour;
        this.manufacturer = manufacturer;
        this.model = model;
        this.variant = variant;
        this.interior = interior;
        this.year = year;
    }

    public void demoMethod() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I'm in a Thread");
            }
        }).start();
    }

    public void demoMethod2() {
        new Thread(() -> System.out.println("I'm in a Thread")).start();
    }

    public void demoMethod3(Runnable r) {
        new Thread(r).start();
    }

    public static String xString() {
        return "This is x: " + x++;
    }

    public String getColour() {
        return colour;
    }

    public void setColour(@NotNull String colour) { // @NotNull comes from JetBrains, not Java. Not enforced by Java.
        this.colour = colour;
    }

    public String getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(@Nullable String manufacturer) {
        this.manufacturer = manufacturer;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getVariant() {
        return variant;
    }

    public void setVariant(String variant) {
        this.variant = variant;
    }

    public @Nullable String getInterior() {
        return interior;
    }

    public void setInterior(String interior) {
        this.interior = interior;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public Object getAnObject() {
        return anObject;
    }

    public void setAnObject(Object anObject) {
        this.anObject = anObject;
    }

    public void variableMethod(int num, String... strings) {
        for (String string: strings) {
            System.out.println(string);
        }
    }

    public void wantsIntArray(int[] theArray) {
        for (int i: theArray) {
            System.out.println(i);
        }
    }

    @Override
    public String toString() {
        return "Car{" +
                "colour='" + colour + '\'' +
                ", manufacturer='" + manufacturer + '\'' +
                ", model='" + model + '\'' +
                ", variant='" + variant + '\'' +
                ", interior='" + interior + '\'' +
                ", year=" + year +
                '}';
    }
}

 

Java-Kotlin Interoperability – Nullability

How to deal with differences in nullability between Java and Kotlin.

fun main() {
    val car = Car("blue", "Ford", "Focus", "SE", "fabric", 2015) // Using Java class, no difference
    // Remember, there are some differences: Java class may require primitive type, so may need to cater for this; also differences in access modifiers
    // Nullability: Kotlin protects against nullability, Java does not. IntellliJ has @NotNull and @Nullable annotations. For documentation only, Java does not enforce, but at least IDE should push for compliance.
    // If Kotlin sees these annotations it will map @NotNull to non-nullable and @Nullable to nullable
    car.colour = "green"
    println(car)
//    car.colour = null // Will throw IllegalArgumentException at compile-time due to @NotNull annotation in Java class
    var manufacturer = car.manufacturer
    println(manufacturer.javaClass) // So is this String variable nullable?
    manufacturer = null // This would be fine with either no annotation or with @Nullable in Java class
    println(manufacturer) // But...
    var model: String = car.model // Non-nullable Kotlin variable declared. We can use this to protect against null values coming in from Java code
//    model = null // Not allowed!
    var variant: String? = car.variant // If we make this variable nullable
    println(variant?.javaClass) // String? is not a subtype of Any as there is no equivalent in Java, so need to add ? to variant
//    var interior: String = car.interior // Not allowed since return type of getInterior is nullable, but Kotlin variable is non-nullable
    // In Java, if a variable is not defined as either Nullable or notNull it is called a platform type. These can't be created in Kotlin.
    // If there is a platform type Kotlin compiler appends the ! symbol to the end of the type, so look out for these in error messages:
    val colour: Int = car.colour // If you hover over car.colour you will see the Found: String! error message - platform type
    // If Java values are not annotated you should perform the usual null checks in Kotlin code - compiler won't do that for you
}
package academy.learnprogamming.javainteroperability;


import org.jetbrains.annotations.NotNull; // N.B. Had to prompt for download from Maven
import org.jetbrains.annotations.Nullable;

public class Car {

    private String colour;
    private String manufacturer;
    private String model;
    private String variant;
    private String interior;
    private int year;

    public Car(String colour, String manufacturer, String model, String variant, String interior, int year) {
        this.colour = colour;
        this.manufacturer = manufacturer;
        this.model = model;
        this.variant = variant;
        this.interior = interior;
        this.year = year;
    }

    public String getColour() {
        return colour;
    }

    public void setColour(@NotNull String colour) { // @NotNull comes from JetBrains, not Java. Not enforced by Java.
        this.colour = colour;
    }

    public String getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(@Nullable String manufacturer) {
        this.manufacturer = manufacturer;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getVariant() {
        return variant;
    }

    public void setVariant(String variant) {
        this.variant = variant;
    }

    public @Nullable String getInterior() {
        return interior;
    }

    public void setInterior(String interior) {
        this.interior = interior;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public String toString() {
        return "Car{" +
                "colour='" + colour + '\'' +
                ", manufacturer='" + manufacturer + '\'' +
                ", model='" + model + '\'' +
                ", variant='" + variant + '\'' +
                ", interior='" + interior + '\'' +
                ", year=" + year +
                '}';
    }
}

 

Kotlin IO

File IO in Kotlin.

// Kotlin simply supplements the existing Java IO libraries with kotlin.io package
// Note text file in base directory of project <-
fun main() {
    File("testfile.txt").reader()
    // Abbreviates the Java declaration: new InputStreamReader(new FileInputStreamReader(new File("testfile.txt")), UTF-8")

    val lines = File("testfile.txt").reader().readLines() // DO NOT USE THIS FUNCTION FOR HUGE FILES. Reads entire file into memory.
    // Closes the Stream for us. Returns listOf<String>
    lines.forEach { println(it)}

    val reader2 = File("testfile.txt").reader()
    val lines2 = reader2.readText() // Returns one String which we would have to parse and close the Stream ourselves
    println("Lines2: $lines2") // Prints fine as text contains newlines
    reader2.close()
    println("======")

    val lines3 = File("testfile.txt").reader().use { it.readText() } // Closes the Reader itself - .use functions close the resource
    println("Lines3: $lines3")
    println("======")

    val lines4 = File("testfile.txt").bufferedReader().use { it.readText() } // BufferedReader
    println("Lines4: $lines4")
    println("======")

    val lines5 = File("testfile.txt").readText() // Version of readText which runs from the File class - limit of 2GB
    println("Lines5: $lines5")
    println("======")

    // If we don't want to read the whole file at once:
    File("testfile.txt").reader().forEachLine { println(it) } // Closes the resource for us
    println("======")

    // If we don't want to read the whole file at once:
    File("testfile.txt").reader().useLines { it.forEach { println(it) } } // useLines returns a reference so we need forEach. More verbose
    println("======")

    // Binary files - best done by using Java methods. No great enhancements in Kotlin.
    val di = DataInputStream(FileInputStream("testfile.bin"))
    var si: String

    try {
        while (true) {
            si = di.readUTF()
            println("Binary file: $si")
        }
    } catch (e: EOFException) {

    }

    // Writing files is no different to Java

    // Try with resources. To make sure a resource is released after using it use try...finally block, or better: try with resources. Kotlin method is to use one of the .use functions (see above)

}

 

Generics

Using generics.

How we would use data type specifications in Java and their benefits:

public class JavaGenerics {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>(); // By giving an indication of data type we have improved error-checking, need less casting and code is clearer

        list.add("Hello");
//        list.add(new BigDecimal(10.5)) // Error-checking picks up on the incompatibility
        list.get(0).toUpperCase(); // IDE suggests functions related to data type

        List list1 = new ArrayList<>(); // However, we can still create a Collection without specifying type

    }
}

The same in Kotlin, introducing Generics:

// Use generics to give the compiler a hint as to what type of objects you are dealing with, often related to Collections
// Allows compiler to do some error-checking at compile time
fun main() {

    val list: MutableList<String> // Kotlin insists on knowing the data type
    list = mutableListOf("Hello")
    list.add("another string")
    printCollection(list)
    list[0].toUpperCase() // We can use the relevant functions

    println("======")

    val bdList = mutableListOf(BigDecimal(-33.45), BigDecimal(3503.99), BigDecimal(0.329))
//    printCollection(bdList) // Won't allow printCollection because it expects String
    printGenericCollection(bdList) // Works because Generics are used

    println("======")

    bdList.printCollectionExtension() // Same result using extension function - IDE suggests

// At runtime the application has none of the Generic information - type erasure. It is simply a syntactical feature e.g. it cannot run 'instanceOf' on a Generic since that information does not exist at runtime.
// Also true of Kotlin since it uses the JVM. How do we use the 'is' operator (equivalent of instanceOf)?
    if (list is List<String>){} // This is allowed! How come, since Generics are lost at runtime? Suspect the function is handled at compile-time by Kotlin
    val listAny: Any = listOf("str1", "str2") // To check this theory...
//    if (listAny is List<String>) {} // This is invalid as the statement cannot be evaluated at compile-time
//    if (listAny is List) // We can't even do this since Kotlin expects a data type
    if (listAny is List<*>) {// So we do this instead - star projection syntax, sort of like wildcard
        println("So let's assume this List contains strings") // If it isn't a List of non-Strings this
        val strList = listAny as List<String> // Casting. This is how we use 'as' in conjunction with this. If it isn't a List of Strings it will throw a ClassCastException. Compiler will warn
        println(strList[1].replace("str", "string"))
    }
}


fun printCollection(collection: List<String>) {
    for (item in collection) {
        println(item)
    }
}

fun <T> printGenericCollection(collection: List<T>) { // The <T> after fun is the type parameter declaration and is necessary
    for (item in collection) {
        println(item)
    }
}

// Extension function example:
fun <T> List<T>.printCollectionExtension() {
    for (item in this) {
        println(item)
    }
}

 

 

Lambdas

Lambdas in Java.

// Easier way to work with interfaces that have just one method that has to be implemented (functional interfaces). Also true if more than one method but other(s) have default implementation
// Often used in place of anonymous classes
public class Lambdas {

    public static void main(String[] args) {
        new Thread(new CodeToRun()).start(); // One method

        new Thread(new Runnable() { // Another method - anonymous class. Still a lot of code to run one line of output
            @Override
            public void run() {
                System.out.println("Also printing from the Runnable");
            }
        }).start();

        // Can be replaced with a lambda
        new Thread(() -> System.out.println("Still printing from the Runnable")).start(); // Passes the println() directly to the Thread constructor
        // 3 parts to a lambda - 1. argument list (empty in this case) 2. arrow token 3. body (put code to be executed here) - use {} for multiple lines (remember ; when multiple lines):

        new Thread(() -> {
            System.out.println("Line one");
            System.out.println("Line two");
        }).start();

        Employee john = new Employee("John Doe", 30);
        Employee tim = new Employee("Tim Buchalka", 21);
        Employee jack = new Employee("Jack Hill", 40);
        Employee snow = new Employee("Snow White", 22);

        List<Employee> employees = new ArrayList<>();
        employees.add(john);
        employees.add(tim);
        employees.add(jack);
        employees.add(snow);

//        Collections.sort(employees, new Comparator<Employee>() {
//            @Override
//            public int compare(Employee employee1, Employee employee2) {
//                return employee1.getName().compareTo(employee2.getName());
//            }
//        });

        Collections.sort(employees, (employee1, employee2) -> employee1.getName().compareTo(employee2.getName()));

        for (Employee employee : employees) {
            System.out.println(employee.getName());
        }

//        String sillyString = doStringStuff(new UpperConcat() {
//            @Override
//            public String upperAndConcat(String s1, String s2) {
//                return s1.toUpperCase() + s2.toUpperCase();
//            }
//        }, employees.get(0).getName(), employees.get(1).getName());
//        System.out.println(sillyString);

        String sillyString = doStringStuff((s1, s2) -> s1.toUpperCase() + s2.toUpperCase(), employees.get(0).getName(), employees.get(1).getName()); // No return keyword required
        System.out.println(sillyString);

    }
    //What if the interface returns a value?
    public final static String doStringStuff(UpperConcat uc, String s1, String s2) {
        return uc.upperAndConcat(s1, s2);
    }
}

class CodeToRun implements Runnable {
    @Override
    public void run() {
        System.out.println("Printing from the Runnable");
    }
}

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

interface UpperConcat {
    public String upperAndConcat(String s1, String s2);
}

 

Kotlin object keyword – Singletons, companion objects and object expressions

Use of the object keyword in Kotlin.

fun main() {
    println(CompanyCommunications.getTagLine()) // Call the class name as there is only one instance
    println(CompanyCommunications.getCopyRightLine())

    SomeOtherClass().printPrivateVar() // Will allow us access to privateVar despite being private, thanks to Companion object
    SomeClass2.SomeCompanion.accessPrivateVar() // Using companion name, but again redundant

    val someClass = SomeClass4.justAssign("this is the string as is")
    val someClass2 = SomeClass4.upperOrLowerCase("this is the string as is", false)
    println(someClass.someString)
    println(someClass2.someString)
//    val someClass3 = SomeClass4("This will not work") // Constructor is private so cannot instantiate directly

    var thisIsMutable = 45

    wantsSomeInterface(object: SomeInterface { // Uses object to create an instance of the someInterface interface - NOT a Singleton. Is generated and then destroyed. Can use multiple interfaces, unlike Java
        override fun mustImplement(num: Int): String {
            return "This is from mustImplement: ${num * 100 + thisIsMutable}" // This expression can access variables from outside it (val or var, doesn't need to be final), unlike Java
        }
    })
}

// 'object' keyword's 3 uses: Singletons, companion objects, object expressions

// Singletons
// //In Java, you would create a private constructor that allows only one instance which other classes can access
// In Kotlin, there can only be one instance of an 'object' class, so we use that:
object CompanyCommunications { // No class keyword needed. Also no constructors as instance is created instantaneously
    val currentYear = Year.now().value
    fun getTagLine() = "Our company rocks!"
    fun getCopyRightLine() = "Copyright \u00A9 $currentYear Our Company. All rights reserved."
}

// Companion Objects
// No static keyword in Kotlin - instead we can use top-level functions and properties, and Object declarations (above)
// But what if you want an equivalent to Java static (see Java objects below), where you can access functions and properties without creating an instance of the class?
// We create companion objects inside the class which can be accessed without having to generate an instance of the class
class SomeClass {

    companion object {
        private var privateVar = 6 // Because is private no getter/setter generated

        fun accessPrivateVar() {
            println("I'm accessing privateVar: $privateVar")
        }
    }

}

class SomeClass2 {

    companion object SomeCompanion { // You can also name your companion object, but little use
        private var privateVar = 6

        fun accessPrivateVar() {
            println("I'm accessing privateVar: $privateVar")
        }
    }

}

class SomeOtherClass() {
    fun printPrivateVar () {
        println(SomeClass.accessPrivateVar()) // Could use SomeClass.Companion.accessPrivateVar() but redundant
    }
}

class SomeClass3 {

    val someString: String

    constructor(str: String) { // First secondary constructor
        someString = str
    }

    constructor(str: String, lowerCase: Boolean) { // Second secondary constructor
        if (lowerCase) {
            someString = str.toLowerCase()
        } else {
            someString = str.toUpperCase()
        }
    }
// But instead of doing it this way we can create a companion class that returns an instance of the class (see below)
}

class SomeClass4 private constructor(val someString: String){ // We want to implement the Factory pattern here. This class should generate instances of the class - nobody should be able to do it directly as in SomeClass3, so primary is made private

    companion object{
        private var privateVar = 6

        fun accessPrivateVar() {
            println("I'm accessing privateVar in SomeClass4: $privateVar")
        }

        fun justAssign(str: String) = SomeClass4(str) // Can only call the private constructor from inside class therefore controlling how class is instantiated...
        fun upperOrLowerCase(str: String, lowerCase: Boolean): SomeClass4 { // so to get an instance of this class you have to go through either the justAssign or upperOrLowerCase function
            if (lowerCase) {
                return SomeClass4(str.toLowerCase())
            } else {
                return SomeClass4(str.toUpperCase())
            }
        }

    }

}

// Object expressions - equivalent to an anonymous object in Java
interface SomeInterface {
    fun mustImplement(num: Int): String
}

fun wantsSomeInterface(si: SomeInterface) {
    println("Printing from wantsSomeInterface - ${si.mustImplement(22)}")
}

Companion object equivalent in Java

public class SomeClass {

    private static int privateVar = 6;

    public static void main(String[] args) {
        new SomeOtherClass().someOtherMethod();
    }

    public static void accessPrivateVar() {
        System.out.println("I'm accessing privateVar: " + privateVar);
    }
}
public class SomeOtherClass {

    public void someOtherMethod() {
        SomeClass.accessPrivateVar();
    }
}

 

Build a database – Room

Code to create a Room database in correspondence with the @Entity and @DAO entries.

Create an abstract class to outline the creation of your table

@Database(entities = {ContactEntry.class}, version = 1, exportSchema = false) // Add @Database annotation and declare class(es) containing @Entity
@TypeConverters(DateConverter.class) // See the @TypeConverters post: https://an.aldezu.com/archives/454 - not in use in this example but included for context
public abstract class AppDatabase extends RoomDatabase { // Extend RoomDatabase

    private static final String LOG_TAG = AppDatabase.class.getSimpleName();
    private static final Object LOCK = new Object();
    private static final String DATABASE_NAME = "contacts"; // Define database name
    private static AppDatabase sInstance;

    public static AppDatabase getInstance(Context context) {
        if (sInstance == null) { // This will only ever generate ONE instance of the AppDatabase (Singleton pattern)
            synchronized (LOCK) {
                Log.d(LOG_TAG, "Creating new database instance");
                sInstance = Room.databaseBuilder(context.getApplicationContext(), // Requires current context, the database class and database name
                        AppDatabase.class, AppDatabase.DATABASE_NAME)
                        .build();
            }
        }
        Log.d(LOG_TAG, "Getting the database instance");
        return sInstance; // Will return new instance if null, old instance if not
    }

    public abstract ContactDao contactDao(); // Create an instance of the DAO for this database

}

To interact with the table you will need a @DAO. To define the table you will need to use @Entity.

@Entity – Room

Defines our SQLite database tables. This example corresponds to the @DAO and Build A Database entries.

Create a custom class to define your table, using Entity to annotate it

@Entity(tableName = "contacts") // Name of table specified as 'contacts'. It is common for database tables and their corresponding classes to not have same name
public class ContactEntry {

    @PrimaryKey(autoGenerate = true) // States that the next variable will be the table's primary key (and therefore unique)
    private int id; // Each member variable corresponds to a column in the table
    private String name; // Each member variable corresponds to a column in the table
    @ColumnInfo(name = "contactAge") // If you wish to specifically state the name of the column use this annotation
    private int age; // Each member variable corresponds to a column in the table

    @Ignore // If you do not want a variable to appear in the table use the @ignore annotation
    private String address;

    @Ignore // Tell Room to use the other constructor (which includes the id field) using the @Ignore annotation, as Room can only use one constructor. This constructor will be used when the user adds a new entry, as they will not know the id of the new entry.
    public ContactEntry (String name, int age) {
        this.description = name;
        this.age = age;
    }

    public ContactEntry (int id, String name, int age) {
        this.id = id;
        this.description = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name= name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

To create the table you will need to Build A Database. To interact with the table you will need to create a @DAO.

ArrayList

Using ArrayLists

    private static final ArrayList<String> arrayList= new ArrayList<>();
    arrayList.add(0, "My String"); //Add to start of ArrayList