2

I found the feature of default argument value in C++ is very useful.

Currently, java doesn't provide this feature natively.

When people need it, they just define a lot of functions with the same name.

This is a very dirty implementation.

So I am wondering are there any more elegant way to do it?

For instance, can I achieve this using annotations?

Any ideas?

Chip Zhang
  • 641
  • 2
  • 11
  • 26
  • 1
    possible duplicate of [Does Java support default parameter values?](http://stackoverflow.com/questions/997482/does-java-support-default-parameter-values) – Stephan Jan 19 '15 at 12:41

4 Answers4

1

I can see two approaches: variadic parameters and annotations.

Here is an often seen approach in Java World:

public void foo() {
    foo(null);
}

public void foo(String bar) {
    if (bar==null) {
        // Set bar to a default value 
        bar = ...; 
    }
}

Here are the workarounds:

Workaround 1: Variadic parameters (Java 5+)

public void foo(String ... params) {
   String bar;
   switch(params.length) {
      case 0:
        // Set bar to a default value 
        bar = ...; 
      break;

      case 1:
        bar = params[0];
      break;

      default:
         throw new RuntimeException( //
                 String.format( //
                    "Unsupported number of parameters (Received: %d; Expected 0 or 1)", //
                     params.length //
               ));
   }
}

Workaround 2: Annotations (Java 5+)

If you implement default parameters with annotations, you will need some kind of framework to process the annotations and call the methods for you. The framework would be in charge to initialize the parameters before calling the method.

For example, when building an API REST with an implementation of JAX-RS, you can rely on this kind of mechanism.

// ...
public Response foo(@DefaultValue("default") String bar) {
    return ...;
}
Stephan
  • 41,764
  • 65
  • 238
  • 329
  • are there some out of box code of the implementation of @DefaultValue for general purpose Java applications – Chip Zhang Jan 19 '15 at 11:00
  • I don't know such an implementation. However, you can check this answer: http://stackoverflow.com/a/19719701/363573. Especially, the option #4 : **Optional class**. – Stephan Jan 19 '15 at 12:44
1

No, java doesn't have an equivalent to C++ default values.

In C++ you might write a function like this

int add(int a, int b = 3)

In Java you can use overloding

public int add(int a){
    add(a, 3);
}

public int add(int a, int b){
    ....
}

From a client's perspective it is equal to default values in c++. E.g.

calc.add(1);
calc.add(1, 2);
René Link
  • 48,224
  • 13
  • 108
  • 140
  • I don't think that it is inelegant, because you explicitly specify that the parameter `b` is optional. I think that the `C++` aproach is more error-prone if you think about refactoring or introducing the default value later. – René Link Jan 19 '15 at 10:10
  • this becomes inelegant when you have a ton of optional parameters. This is one of the reasons some people like the BuilderPattern, e.g., http://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html – Tommy Oct 14 '15 at 15:35
  • Even if this way is deemed better, overloading is also present in C++. For constructors, I like its delegate constructor syntax better than the "must call `this()` or `super()` in the first line" approach. – T Tse May 29 '20 at 03:45
1

To use annotations for this you need a wrapper over the method that reads and modifies the parameters based on the annotations and the incoming parameters.

If access to these methods is controlled by a context (ex: methods in spring beans) you can implement this rather easy. You may want to consider the delay introduced by a proxy and also to make sure that all calls are done through the proxy (no local calls).

Cristian Sevescu
  • 1,364
  • 8
  • 11
1

You can do it with custom annotations. Here is an example:

Firstly define the annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) 
public @interface DefaultValue {
    String defaultValue() default "";
}

The @Target specifies the type of the Annotation, the possible targets are:

ElementType.ANNOTATION_TYPE
ElementType.CONSTRUCTOR
ElementType.FIELD
ElementType.LOCAL_VARIABLE
ElementType.METHOD
ElementType.PACKAGE
ElementType.PARAMETER
ElementType.TYPE

Now, for instance, you have a UserName object, that is created when a new user is created.

public class UserName {

    @DefaultValue(defaultValue = "<empty>")
    private String name;

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

    public String getName() {
        return this.name;
    }

    public String toString() {
        return "Username is: " + this.name;
    }
}

The new username Object may or may not contain a name, so we annotate it with the annotation DefaultValue, and pass the annotation the string <empty>. Once the object is processed, it can be check whether or not the default value should be used or not:

public class CreateName {
    public static void main (String [] args) throws NoSuchFieldException, SecurityException {
        System.out.println(checkUserName(new UserName()));
    }

    public static UserName checkUserName(UserName user) throws NoSuchFieldException, SecurityException {
        if (user.getName() == null) {
            Field userNameField = UserName.class.getDeclaredField("name");

            if (userNameField.isAnnotationPresent(DefaultValue.class)) {
                Annotation ann = userNameField.getAnnotation(DefaultValue.class);
                DefaultValue value = (DefaultValue) ann;
                user.setName(value.defaultValue());
            }
        }
        return user;
    }
}

This is a simple example but I hope it can help you.

Note:

If you do not want to specify the default value for every field, you can also simple annotate the field like so:

@DefaultValue
private String name;

And the default value defined in the DefaultValue class will be used (in my example, it would default to the empty string "")

Ian2thedv
  • 2,691
  • 2
  • 26
  • 47