Thor
Thor

Reputation: 10068

Does Java support Swift-like class extensions?

In Swift, you can create extension of existing class to add additional functions to the existing class whenever it is needed. This also helps to avoid creating a subclass of the existing class.

I was just wondering if there is a similar function exist in Java? or is it the only way to add additional methods to a existing Java class is to create a subclass of the existing class?

Upvotes: 17

Views: 5335

Answers (4)

Gregory Ledenev
Gregory Ledenev

Reputation: 1

(Disclosure: I am the owner of the linked repo)

Java does not have built-in support for class (category) extensions, and it is unlikely that it will be added anytime soon. To address this missing functionality, I've made a small library - Java Class Extension Library that provides an ability to emulate class extensions (categories) in Java.

The library supports the following approaches for creating of class extensions:

  1. Static Class Extensions: define and implement extensions as usual Java classes and then utilize the Java Class Extension library to find matching extensions.
  2. Dynamic Class Extensions: utilize the Java Class Extension library to define extensions by composing them as sets of lambda operations and let the library create extensions dynamically on the fly.

Both approaches leverage the ClassExtension interface, which facilitates querying for an extension based on an object's extension interface. Once obtained, these extensions unlock additional functionality with remarkable ease. For example, obtaining a Shippable extension and using its ship() method to perform shipping a book would look like:

Book book = new Book("The Mythical Man-Month");
Shippable shippable = StaticClassExtension.sharedExtension(book, Shippable.class);
shippable.ship();

or

Book book = new Book("The Mythical Man-Month");
Shippable shippable = DynamicClassExtension.sharedExtension(book, Shippable.class);
shippable.ship();

Shipping a collection of items is equally straightforward:

Item[] items = {
    new Book("The Mythical Man-Month"), 
    new Furniture("Sofa"), 
    new ElectronicItem("Soundbar")
};

for (Item item : items) {
    Shippable shippable = StaticClassExtension.sharedExtension(item, Shippable.class);
    item.ship();
}

Upvotes: -1

Krzysztof Atłasik
Krzysztof Atłasik

Reputation: 22635

It can be done in other languages for JVM, like Scala, Groovy or Closure.

For example in Groovy:

List.metaClass.printSize = {
    println delegate.size()
}

[1,2,3].printSize() //prints 3

In Scala you can use implicit class:

implicit class PrefixedString(val s: String) {
   def prefix = "prefix_" + s 
}

"foo".prefix // returns "prefix_foo"

Please have a look at this article.

An important remark is that Groovy/Scala source code is intended to be compiled to Java bytecode so that the resulting classes can be used in Java code.

Upvotes: 2

Czyzby
Czyzby

Reputation: 3139

No, vanilla Java does not feature extension methods. However, Lombok adds many useful features - including extension methods syntax - thanks to its annotations and bytecode generation.

You can use its @ExtensionMethod annotations to "convert" existing static methods to extension methods. The first parameter of the static methods basically becomes this. For example, this is a valid Lombok-enhanced Java code:

import lombok.experimental.ExtensionMethod;

@ExtensionMethod({java.util.Arrays.class, Extensions.class})
public class ExtensionMethodExample {
  public String test() {
    int[] intArray = {5, 3, 8, 2};
    intArray.sort();

    String iAmNull = null;
    return iAmNull.or("hELlO, WORlD!".toTitleCase());
  }
}

class Extensions {
  public static <T> T or(T obj, T ifNull) {
    return obj != null ? obj : ifNull;
  }

  public static String toTitleCase(String in) {
    if (in.isEmpty()) return in;
    return "" + Character.toTitleCase(in.charAt(0)) +
        in.substring(1).toLowerCase();
  }
}

Note that Lombok extension methods can be "invoked" on null objects - as long as the static method is null-safe, NullPointerException will not be thrown, as this is basically translated to static method call. Yes - it comes down to syntax sugar, but I guess this is still more readable than the usual static methods calls.

Aside from that, you can use some other JVM language with Java interoperability, if that's OK in your project. For example, Kotlin comes with extension methods functionality, as well as some useful extensions already defined in the standard library. Here's a Kotlin and Lombok comparison.

Upvotes: 8

Jiri Tousek
Jiri Tousek

Reputation: 12450

The Decorator Pattern is perhaps the closest match. It uses interface to maintain the type compatibility and composition to enhance the existing class' function. It's not the same principle as the one you're describing but might serve the same purpose.

Upvotes: 2

Related Questions