Java and Kotlin: A Practical comparison (part II)
Tags: java, kotlin, designpatterns
Published: 2024-01-04 01:26:26

## Design Patterns

We will analyze how some design patterns are implemented in both languages.

### 1.- Optional Pattern

In Java, Optional doesn't solve the Null Pointer Exception or NPE problem. It just wraps it and "protects" our return values.

```java
Optional<String> getCity(String user) {
  var city = getOptionalCity(user);
  if (city != null) 
    return Optional.of(city);
  else
    return Optional.empty();
}
```

```java
Optional.ofNullable(null)
        .ifPresentOrElse(
                email -> System.out.println("Sending email to " + email),
                ()    -> System.out.println("Cannot send email"));
```
Optional is useful for returning types, but it should not be used on parameters or properties.

```java
getPermissions(user, null);
getPermissions(user, Optional.empty());  // Not recommended
```

**KOTLIN**

Solution: Nullability is built into the type system. Kotlin embraces null.
*String?* and *String* are different types. *T* is a subtype of *T?*.

```kotlin
val myString: String = "hello"
val nullableString: String? = null   // correct!!
```

In Kotlin, all regular types are non-nullable by default unless you explicitly mark them as nullable. If you don't expect a function argument to be null, declare the function as follows:

```kotlin
fun stringLength(a: String) = a.length
```

The parameter *a* has the String type, which in Kotlin means it must always contain a String instance and it cannot contain null.
An attempt to pass a null value to the *stringLength(a: String)* function will result in a compile-time error.

This works for parameters, return types, properties and generics.

```kotlin
val list: List<String>
list.add(null)   // Compiler error
```

### 2.- Overloading Methods

```java
void log(String msg) { ......... };
void log(String msg, String level) { ......... };
void log(String msg, String level, String ctx) { ......... };
```

**KOTLIN**

In kotlin we declare only one function, because we have default arguments and named arguments.

```kotlin
fun log(
    msg: String, 
    level: String = "INFO", 
    ctx: String = "main"
) { 
......... 
}
```

```kotlin
log(level="DEBUG", msg="trace B")
```

### 3.- Utility static methods

```java
final class NumberUtils {
  public static boolean isEven(final int i) {
    return i % 2 == 0;
  }
}
```

In some projects we may end up declaring the same utility function more than once.

**KOTLIN**

```kotlin
fun Int.isEven() = this % 2 == 0  // Extension function

2.isEven()
```

### 4.- Factory

```java
public class NotificationFactory {

  public static Notification createNotification(
        final NotificationType type
  ) {
      return switch(type) {
        case Email -> new EmailNotification();
        case SMS -> new SmsNotification();
      };
  }
}
```

**KOTLIN**

In Kotlin a function is used instead of an interface.

```kotlin
//  This would be a code smell in Java
fun Notification(type: NotificationType) = when(type) {
    NotificationType.Email -> EmailNotification()
    NotificationType.SMS -> SmsNotification()
  }
}

val notification = Notification(NotificationType.Email)
```

### 5.- Singleton

```java
// Much code, it's not even thread-safe
public final class MySingleton {
    private static final MySingleton INSTANCE;

    private MySingleton() {}

    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new MySingleton();
        }
        return INSTANCE;
    }
}
```

**KOTLIN**

This pattern is built into the Kotlin language. It's lazy and thread-safe.

```kotlin
object Singleton {
  val myProperty......
  fun myInstanceMethod() {
    ...............
  }
}
```

### 6.- Iterator

This can be applied only to collections, not to user defined classes.

```java
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");

var iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);   // A, B, C
}
```

**KOTLIN**

```kotlin
val list = listOf("A", "B", "C")
for (elem in list) {
  println(elem)
}
```

This can be applied to any class that has the **iterator** operator function defined.

```kotlin
class School(
  val students: List<Student> = listOf(),
  val teachers: List<Teacher> = listOf()
)

operator fun School.iterator() = iterator<Person> {  // Extension function
  yieldAll(teachers)
  yieldAll(students)
}

val mySchool = School()
for (person in mySchool) {
  println(person)
}
```

Likewise, the operator function **compareTo** must be used to compare objects. 

### 7.- Comparable

```kotlin
class School(val students: List<Student>, val teachers: List<Teacher>) 

override fun School.compareTo(other: School) =
    students.size.compareTo(other.students.size)

fun main() {
    val school1 = School(listOf(Student("John"), Student("Alice")), listOf(Teacher("Mr. Smith")))
    val school2 = School(listOf(Student("Bob"), Student("Eve"), Student("Carol")), listOf(Teacher("Mrs. Johnson")))

    if (school1 > school2) {
        println("$school1 has more students than $school1")
    }
}
```

### 8.- Strategy pattern

**Implementation with interfaces**

This is the classical approach, shown in Kotlin.

```kotlin
fun interface PaymentStrategy {
    fun charge(amount: BigDecimal) : PaymentState
}
```

Next, we implement the interface for all the different payment methods we want to support:

```kotlin
class CreditCardPaymentStrategy : PaymentStrategy {
    override fun charge(amount: BigDecimal) : PaymentState = PaymentState.PAID
}

class PayPalPaymentStrategy : PaymentStrategy {
    override fun charge(amount: BigDecimal) = PaymentState.PAID
}
```

This is the resulting class:

```kotlin
class ShoppingCart2(private val paymentStrategy: PaymentStrategy) {
    fun process(totalPrice: BigDecimal) = paymentStrategy.charge(totalPrice)
}
```

**Implementation with Function Types**

This implementation is easier to read than the previous one, but it's less reusable and less maintainable.

```kotlin
class ShoppingCart(private val paymentProcessor: (BigDecimal) -> PaymentState) {
    fun process(totalPrice: BigDecimal) = paymentProcessor(totalPrice)
}

typealias PaymentStrategy = (BigDecimal) -> PaymentState
class ShoppingCart(private val paymentProcessor: PaymentStrategy) {
    fun process(totalPrice: BigDecimal) = paymentProcessor(totalPrice)
}
```

This is how it's used:

```kotlin
val creditCardPaymentProcessor = { amount: BigDecimal -> ... }

val payPalPaymentProcessor = { amount: BigDecimal -> ... }
```

**JAVA

In Java, function types have a strange syntax.

```java
interface PaymentProcessor {
    public Function<BigDecimal, PaymentState> process;
};
```

This is how it's used:

```java
class creditCardPaymentProcessor implements PaymentProcessor {
    @Override
    public Function<BigDecimal, PaymentState> process = .....;
};
```

It's quite annoying having to create a class per strategy.