3

I am posting a C# example of extension usage, to make my question more clear. I have a simple class called Parameter with two properties: a key and a value. And I am extending the List of Parameters to be able to check if a certain key is contained in the List:

Parameter Class:

public class Parameter
{
    private String key { get; set; }
    private String value { get; set; }
}

Parameter Extension Class:

public static class ParameterListExtension
{
    public static bool contain(this List<Parameter> parameters, String key)
    {
        foreach (Parameter parameter in parameters) {
            if (parameter.key.Equals(key)) { return true; } }
        return false;
    }
}

Usage of Extension:

List<Parameter> parameters = getParameters();
if (parameters.contain("myParameter")) { ... }

Can this be done in Java?

Stefanos Kargas
  • 10,547
  • 22
  • 76
  • 101

4 Answers4

2

There is an extension to Java, called Xtend, that adds support for extension methods (among other features). Some of the features of Xtend are supposed to come with Java 8. In my experiance, Xtend is sometimes nice, especially when writing tests, but the tool support in Ecplise is far worse than for pure Java. As far as I know there are no other IDEs supporting Xtend.

Sven Amann
  • 565
  • 2
  • 12
2

In Java 7 and earlier, there is no way to do this as described. The solution is to use a "helper" class as described in the other answers.

In Java 8, you can "sort of" do this using default methods. Consider the following:

public interface Parameter {
    // getters and setters
}

public class ParameterImpl implements Parameter {
    // Implements the getters and setters and the state variables.
}

Now suppose that we modify the Parameter as follows:

public interface Parameter {
    // getters and setters as before

    public default boolean contain(this List<Parameter> parameters, String key) {
        // (Do not copy this!  There are better ways to code this in Java 8 ...
        //  ... but that is beside the point.)
        for (Parameter parameter : parameters) {
            if (parameter.getKey().equals(key)) { 
                 return true; 
            } 
        }
        return false;
    }
}

We can make this change to the interface (in the forward direction) without modifying the classes that implement the interface, and without breaking binary compatibility.

Of course, this only works if we had the foresight to create a separate interface and class. (But if we didn't do that, I would have thought is was no a "big deal" to modify the Parameter class to add the extension method.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • This code does not compile. The default method signature should be `default boolean contain(List parameters, String key) {`. It's probably better to write it this way: `static boolean contains(List parameters, String key) { return parameters.stream().anyMatch(p->p.getKey().equals(key)); }` – ngreen Sep 03 '14 at 18:01
  • @ngreen - I fixed the compilation error. Thanks. – Stephen C Sep 03 '14 at 22:33
  • Is `this` in the method parameter used the same in Java 8 as in C#? – Arturo Torres Sánchez Oct 23 '14 at 15:49
1

There is no such mechanism in Java to extend the behavior of a defined class out of your control. Alternatively, helper class and interface can be defined and used, though they don't 100% serve the purpose especially when visibility is a concern.

Alex Suo
  • 2,977
  • 1
  • 14
  • 22
  • Extension methods extend a _type_. So, they can also be use to extend behavior of objects implementing an _interface_. – Tom Blodget Sep 24 '13 at 10:39
0
public class ParameterListExtension
{
  public static boolean contain(List<Parameter> parameters, String key)
  {
    for(Parameter parameter:parameters)
      if(parameter.key.equals(key)) return true;
    return false;
  }
}

import static ParameterListExtension.contain;
…
List<Parameter> parameters = getParameters();
if(contain(parameters, "myParameter")) { ... }

I don’t see the advantage of obfuscating where the method came from and pretending it was an instance method of the list.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • 13
    Have a look at LINQ and how it would look like without extension methods. This should show the advantage. It certainly isn't about obfuscation. – Daniel Hilgarth Sep 24 '13 at 09:45
  • 1
    There is no LINQ in Java. And the idea of LINQ is questionable too, but that’s out of the scope of the question. The question was about extension methods and nothing else. – Holger Sep 24 '13 at 09:47
  • 2
    "I don’t see the advantage of obfuscating where the method came from and pretending it was an instance method of the list." Because it keeps you from parenthesis pile-up and distancing between a method name and its parameters, as seen in e.g.: `import static ListExtensions.*; var unitNames = JoinUsing(Select(Where(list, a=>a.type == "unit"), a=>a.name), " ");` Compare to the C#: `using ListExtensions; var unitNames = list.Where(a=>a.type == "unit").Select(a=>a.name).JoinUsing(" ");` – Venryx Aug 09 '16 at 03:48
  • @Venryx: tell that LISP developers ;-) Seriously, if you want to support chainable operations (in Java) you should simply return a custom type from the first method rather than a type that will again require an “extension method”… – Holger Aug 16 '16 at 08:29