Varargs method parameter

Figure 452. Expecting one int argument Slide presentation
Code
public class Q {

    static void main() {
        printInfo("Winner", 34);
    }

    public static void printInfo(String msg, int value) {
        System.out.println(msg + ": " + value);
    }
}
Result
Winner: 34

Figure 453. One, two or three int arguments by overloading Slide presentation
Code
printInfo("Winner", 34);         // One int value
printInfo("Winner", 31, 7);      // Two int values
printInfo("Winner", 2, 8, 5);    // Three int values
---------------------------------------------------------------------------------
public static void printInfo(String msg, int value) { ...}

public static void printInfo(String msg, int value1, int value2) {
    System.out.println(msg + ": " + value1 + " " + value2 );
}
public static void printInfo(String msg, int value1, int value2, int value3) {
    System.out.println(msg + ": " + value1 + " " + value2 + " " + value3);
}
Result
Winner: 34
Winner: 31 7
Winner: 2 8 5

Figure 454. Observations Slide presentation
  • Similar code in multiply overloaded methods.

  • Tedious: Each added argument requires adding another method.

Objective: Get rid of boilerplate code!


Figure 455. Arbitrary number of arguments by array Slide presentation
Code
printInfo("Winner", new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
---------------------------------------------------------------------------------
public static void printInfo(String msg, int[] values) {
    System.out.print(msg + ": " );
    for (int v: values) {
        System.out.print(v + " ");
    }
    System.out.println();
}
Result
Winner: 1 2 3 4 5 6 7 8 9 

Figure 456. Vararg: Syntactic sugar by ellipsis »...« Slide presentation
Code
printInfo("Winner", new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); // Array of int

printInfo("Winner", 20, 19, 18, 17, 16, 15);                  // Separate values
---------------------------------------------------------------------------------
public static void printInfo(String msg, int... values) {
    System.out.print(msg + ": " );
    for (int v: values) {
        System.out.print(v + " ");
    }
    System.out.println();
}
Result
Winner: 1 2 3 4 5 6 7 8 9 
Winner: 20 19 18 17 16 15 

Figure 457. Varargs preconditions Slide presentation
  • Only one varargs parameter per method.

  • Must be a method's last argument.


Figure 458. Further reading on varargs Slide presentation

exercise No. 147

Creating a flexible max(...) method.

Q:

Get inspired by Math.max() and extend it to a method of your own allowing for an arbitrary number of arguments to be used like e.g:

Code
System.out.println(max(1, 6, 0, -3, 20));
Result
20

A:

The varargs mechanism allows for defining:

/**
 * <p>Get the maximum from a list of values.</p>
 * @param values At least one value.
 *
 * @return The largest of all arguments.
 */
public static int max(int ... values) {
   int max = values[0];
   for (int i = 1; i < values.length; i++) {
      max = Math.max(max, values[i]);
   }
   return max;
}

exercise No. 148

Enforcing mandatory arguments

Q:

As part of its contract being stated by the max(...) method's documentation the previous solution requires at least one argument. Violating this contract is a recipe for disaster:

Code
System.out.println(max()); // No argument
Result
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
    at de.hdm_stuttgart.App.max(App.java:18)
    at de.hdm_stuttgart.App.main(App.java:9)

Unfortunately this error does not show up at compile-time but sadly not until run-time and may thus represent a hidden flaw.

Question: Why can't we solve this issue by just changing the implementation?

Instead modify:

  1. The method's signature requiring at least two values at compile time.

  2. The method's implementation.

A:

By its signature the max(...) method must return a value. Mitigation by changing just its implementation is impossible to achieve since there is no plausible way defining an empty list's maximum value.

Changing both our method's signature and implementation is the way to go:

/**
 * <p>Get the maximum from a list of values.</p>
  *
  * @param value1 The first value.
  * @param value2 The second value.
  * @param values Additional optional values.
  *
  * @return The largest of all arguments.
  */
public static int max(int value1, int value2, int ... values) {
   int max = Math.max(value1, value2);
   for (int i:  values) {
      max = Math.max(max, i);
   }
   return max;
}

Now a minimum of two arguments is being required. Violation yields a compile-time rather than a (sometimes too late) run-time error:

Code
System.out.println(max()); // No argument
Result
Cannot resolve method 'max()'