Home Does Java support default parameter values?
Reply: 19

Does Java support default parameter values?

gnavi
1#
gnavi Published in 2009-06-15 18:04:28Z

I came across some Java code that had the following structure:

public MyParameterizedFunction(String param1, int param2)
{
    this(param1, param2, false);
}

public MyParameterizedFunction(String param1, int param2, boolean param3)
{
    //use all three parameters here
}

I know that in C++ I can assign a parameter a default value. For example:

void MyParameterizedFunction(String param1, int param2, bool param3=false);

Does Java support this kind of syntax? Are there any reasons why this two step syntax is preferable?

Peter Mortensen
2#
Peter Mortensen Reply to 2013-09-13 17:12:48Z

No, the structure you found is how Java handles it (that is, with overloading instead of default parameters).

For constructors, See Effective Java: Programming Language Guide's Item 1 tip (Consider static factory methods instead of constructors) if the overloading is getting complicated. For other methods, renaming some cases or using a parameter object can help. This is when you have enough complexity that differentiating is difficult. A definite case is where you have to differentiate using the order of parameters, not just number and type.

Rob H
3#
Rob H Reply to 2009-06-15 18:05:16Z

Sadly, no.

Peter Mortensen
4#
Peter Mortensen Reply to 2013-09-13 17:13:45Z

No.

You can achieve the same behavior by passing an Object which has smart defaults. But again it depends what your case is at hand.

tomjen
5#
tomjen Reply to 2009-06-15 18:49:17Z

No. In general Java doesn't have much (any) syntactic sugar, since they tried to make a simple language.

Community
6#
Community Reply to 2017-05-23 12:34:53Z

No, but you can use the Builder Pattern, as described in this Stack Overflow answer.

As described in the linked answer, the Builder Pattern lets you write code like

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

in which some fields can have default values or otherwise be optional.

Nicholas Jordan
7#
Nicholas Jordan Reply to 2009-09-28 02:33:40Z

There are half a dozen or better issues such as this, eventually you arrive at the static factory pattern ... see the crypto api for that. Sort difficult to explain, but think of it this way: If you have a constructor, default or otherwise, the only way to propagate state beyond the curly braces is either to have a Boolean isValid; ( along with the null as default value v failed constructor ) or throw an exception which is never informative when getting it back from field users.

Code Correct be damned, I write thousand line constructors and do what I need. I find using isValid at object construction - in other words, two line constructors - but for some reason I am migrating to the static factory pattern. I just seems you can do a lot if you in a method call, there are still sync() issues but defaults can be 'substituted' better ( safer )

I think what we need to do here is address the issue of null as default value vis-a-vis something String one=new String(""); as a member variable, then doing a check for null before assigning string passed to the constructor.

Very remarkable the amount of raw, stratospheric computer science done in Java.

C++ and so on has vendor libs, yes. Java can outrun them on large scale servers due to it's massive toolbox. Study static initializer blocks, stay with us.

ebelisle
8#
ebelisle Reply to 2013-10-03 21:37:48Z

Unfortunately, yes.

void MyParameterizedFunction(String param1, int param2, bool param3=false) {}

could be written in Java 1.5 as:

void MyParameterizedFunction(String param1, int param2, Boolean... params) {
    assert params.length <= 1;
    bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}

But whether or not you should depend on how you feel about the compiler generating a

new Boolean[]{}

for each call.

For multiple defaultable parameters:

void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}

could be written in Java 1.5 as:

void MyParameterizedFunction(String param1, int param2, Object... p) {
    int l = p.length;
    assert l <= 2;
    assert l < 1 || Boolean.class.isInstance(p[0]);
    assert l < 2 || Integer.class.isInstance(p[1]);
    bool param3 = l > 0 && p[0] != null ? ((Boolean)p[0]).booleanValue() : false;
    int param4 = l > 1 && p[1] != null ? ((Integer)p[1]).intValue() : 42;
}

This matches C++ syntax, which only allows defaulted parameters at the end of the parameter list.

Beyond syntax, there is a difference where this has run time type checking for passed defaultable parameters and C++ type checks them during compile.

om-nom-nom
9#
om-nom-nom Reply to 2012-04-03 13:58:02Z

You can do this is in Scala, which runs on the JVM and is compatible with Java programs. http://www.scala-lang.org/

i.e.

class Foo(var prime: Boolean = false, val rib: String)  {}
hoaz
10#
hoaz Reply to 2012-12-13 17:15:14Z

It is not supported but there are several options like using parameter object pattern with some syntax sugar:

public class Foo() {
    private static class ParameterObject {
        int param1 = 1;
        String param2 = "";
    }

    public static void main(String[] args) {
        new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
    }

    private void myMethod(ParameterObject po) {
    }
}

In this sample we construct ParameterObject with default values and override them in class instance initialization section { param1 = 10; param2 = "bar";}

IronWolf
11#
IronWolf Reply to 2013-02-18 14:05:09Z

I might be stating the obvious here but why not simply implement the "default" parameter yourself?

public class Foo() {
        public void func(String s){
                func(s, true);
        }
        public void func(String s, boolean b){
                //your code here
        }
}

for the default you would ether use

func("my string");

and if you wouldn't like to use the default, you would use

func("my string", false);

Vitalii Fedorenko
12#
Vitalii Fedorenko Reply to 2016-09-02 02:35:38Z

There are several ways to simulate default parameters in Java:

  1. Method overloading.

    void foo(String a, Integer b) {
        //...
    }
    
    void foo(String a) {
        foo(a, 0); // here, 0 is a default value for b
    }
    
    foo("a", 2);
    foo("a");
    

    One of the limitations of this approach is that it doesn't work if you have two optional parameters of the same type and any of them can be omitted.

  2. Varargs.

    a) All optional parameters are of the same type:

    void foo(String a, Integer... b) {
        Integer b1 = b.length > 0 ? b[0] : 0;
        Integer b2 = b.length > 1 ? b[1] : 0;
        //...
    }
    
    foo("a");
    foo("a", 1, 2);
    

    b) Types of optional parameters may be different:

    void foo(String a, Object... b) {
        Integer b1 = 0;
        String b2 = "";
        if (b.length > 0) {
          if (!(b[0] instanceof Integer)) { 
              throw new IllegalArgumentException("...");
          }
          b1 = (Integer)b[0];
        }
        if (b.length > 1) {
            if (!(b[1] instanceof String)) { 
                throw new IllegalArgumentException("...");
            }
            b2 = (String)b[1];
            //...
        }
        //...
    }
    
    foo("a");
    foo("a", 1);
    foo("a", 1, "b2");
    

    The main drawback of this approach is that if optional parameters are of different types you lose static type checking. Furthermore, if each parameter has different meaning you need some way to distinguish them.

  3. Nulls. To address the limitations of the previous approaches you can allow null values and then analyse each parameter in a method body:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);
    

    Now all arguments values must be provided, but the default ones may be null.

  4. Optional class. This approach is similar to nulls, but uses Java 8 Optional class for parameters that have a default value:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());
    

    Optional makes a method contract explicit for a caller, however, one may find such signature too verbose.

  5. Builder pattern. The builder pattern is used for constructors and is implemented by introducing a separate Builder class:

     class Foo {
         private final String a; 
         private final Integer b;
    
         Foo(String a, Integer b) {
           this.a = a;
           this.b = b;
         }
    
         //...
     }
    
     class FooBuilder {
       private String a = ""; 
       private Integer b = 0;
    
       FooBuilder setA(String a) {
         this.a = a;
         return this;
       }
    
       FooBuilder setB(Integer b) {
         this.b = b;
         return this;
       }
    
       Foo build() {
         return new Foo(a, b);
       }
     }
    
     Foo foo = new FooBuilder().setA("a").build();
    
  6. Maps. When the number of parameters is too large and for most of them default values are usually used, you can pass method arguments as a map of their names/values:

    void foo(Map<String, Object> parameters) {
        String a = ""; 
        Integer b = 0;
        if (parameters.containsKey("a")) { 
            if (!(parameters.get("a") instanceof Integer)) { 
                throw new IllegalArgumentException("...");
            }
            a = (String)parameters.get("a");
        }
        if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 
    

Please note that you can combine any of these approaches to achieve a desirable result.

Hamzeh Soboh
13#
Hamzeh Soboh Reply to 2014-09-03 16:45:05Z

Try this solution:

public int getScore(int score, Integer... bonus)
{
    if(bonus.length > 0)
    {
        return score + bonus[0];
    }

    return score;
}
peterh
14#
peterh Reply to 2017-10-18 03:39:53Z

No, but you can very easily emulate them. What in C++ was:

public: void myFunction(int a, int b=5, string c="test") { ... }

In Java, it will be an overloaded function:

public void myFunction(int a, int b, string c) { ... }

public void myFunction(int a, int b) {
    myFunction(a, b, "test");
}

public void myFunction(int a) {
    myFunction(a, 5);
}

Earlier was mentioned, that default parameters caused ambiguous cases in function overloading. That is simply not true, we can see in the case of the C++: yes, maybe it can create ambiguous cases, but these problem can be easily handled. It simply wasn't developed in Java, probably because the creators wanted a much simpler language as C++ was - if they had right, is another question. But most of us don't think he uses Java because of its simplicity.

Michael Sims
15#
Michael Sims Reply to 2015-01-18 15:40:19Z

This is how I did it ... it's not as convenient perhaps as having an 'optional argument' against your defined parameter, but it gets the job done:

public void postUserMessage(String s,boolean wipeClean)
{
    if(wipeClean)
    {
        userInformation.setText(s + "\n");
    }
    else
    {
        postUserMessage(s);
    }
}

public void postUserMessage(String s)
{
    userInformation.appendText(s + "\n");
}

Notice I can invoke the same method name with either just a string or I can invoke it with a string and a boolean value. In this case, setting wipeClean to true will replace all of the text in my TextArea with the provided string. Setting wipeClean to false or leaving it out all together simply appends the provided text to the TextArea.

Also notice I am not repeating code in the two methods, I am merely adding the functionality of being able to reset the TextArea by creating a new method with the same name only with the added boolean.

I actually think this is a little cleaner than if Java provided an 'optional argument' for our parameters since we would need to then code for default values etc. In this example, I don't need to worry about any of that. Yes, I have added yet another method to my class, but it's easier to read in the long run in my humble opinion.

Tomas Bjerre
16#
Tomas Bjerre Reply to 2016-06-13 17:42:50Z

You may use Java Method Invocation Builder to automatically generate the builder with default values.

Just add @GenerateMethodInvocationBuilder to the class, or interface, and the @Default to parameters in methods where you want default values. A builder will be generated at compile time, using the default values that you specified with your annotations.

@GenerateMethodInvocationBuilder
public class CarService {
 public CarService() {
 }

 public String getCarsByFilter(//
   @Default("Color.BLUE") Color color, //
   @Default("new ProductionYear(2001)") ProductionYear productionYear,//
   @Default("Tomas") String owner//
 ) {
  return "Filtering... " + color + productionYear + owner;
 }
}

And then you can invoke the methods.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .invoke(instance);

Or set any of the default values to something else.

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
Community
17#
Community Reply to 2017-05-23 11:47:32Z

A similar approach to https://stackoverflow.com/a/13864910/2323964 that works in Java 8 is to use an interface with default getters. This will be more whitespace verbose, but is mockable, and it's great for when you have a bunch of instances where you actually want to draw attention to the parameters.

public class Foo() {
    public interface Parameters {
        String getRequired();
        default int getOptionalInt(){ return 23; }
        default String getOptionalString(){ return "Skidoo"; }
    }

    public Foo(Parameters parameters){
        //...
    }

    public static void baz() {
        final Foo foo = new Foo(new Person() {
            @Override public String getRequired(){ return "blahblahblah"; }
            @Override public int getOptionalInt(){ return 43; }
        });
    }
}
Umair Khalid
18#
Umair Khalid Reply to 2016-09-01 06:51:15Z

NO, But we have alternative in the form of function overloading.

called when no parameter passed

void operation(){

int a = 0;
int b = 0;

} 

called when "a" parameter was passed

void operation(int a){

int b = 0;
//code

} 

called when parameter b passed

void operation(int a , int b){
//code
} 
simhumileco
19#
simhumileco Reply to 2017-11-22 18:44:22Z

No, but the simplest way to implement this is:

public MyParameterizedFunction(String param1, int param2, Boolean param3) {

    param3 = param3 == null ? false : param3;
}

public MyParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

Or instead of the ternary operator you can use if:

public MyParameterizedFunction(String param1, int param2, Boolean param3) {

    if (param3 == null) {
        param3 = false;
    }
}

public MyParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
mrts
20#
mrts Reply to 2017-11-26 19:51:08Z

As Scala was mentioned, Kotlin is also worth mentioning. In Kotlin function parameters can have default values as well and they can even refer to other parameters:

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
    ...
}

Like Scala, Kotlin runs on the JVM and can be easily integrated into existing Java projects.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.391239 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO