Varargs method parameter

Figure 397. Expecting one int argument Slide presentation
Code
static void main() {
  printInfo("Winner", 34);
}

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

Figure 398. 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) {
    IO.println(msg + ": " + value1 + " " + value2 );
}
public static void printInfo(String msg, , int value1, int value2, int value3) {
    IO.println(msg + ": " + value1 + " " + value2 + " " + value3);
}
Result
Winner: 34
Winner: 31 7
Winner: 2 8 5

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

  • Tedious: Each added argument requires adding another method.

Objective: Get rid of boilerplate code!


Figure 400. 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) {
    IO.print(msg + ": " );
    for (int v: values) {
        IO.print(v + " ");
    }
    IO.println();
}
Result
Winner: 1 2 3 4 5 6 7 8 9

Figure 401. Observations Slide presentation
  • Clumsy, requires

    printInfo("Winner", new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });

    rather than

    printInfo("Winner", { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); // Syntax error

Objective: Simplify parameter passing


Figure 402. Vararg: Syntactic sugar by ellipsis »...« Slide presentation
Code
final int[] values = { 1, 2, 3, 4, 5, 6, 7, 8, 9};

printInfo("Winner", values);                 // Array of int

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

Figure 403. Varargs: Generalizing arrays Slide presentation
  • Replace

    printInfo(String msg, int[] values)
  • By

    printInfo(String msg, int ... values)

Figure 404. Using varargs Slide presentation
  • Only one varargs parameter per method.

  • Must be the method's last argument.


Figure 405. 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
IO.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 being stated in the max(...) method's documentation the previous solution requires at least one argument. Violating this contract is a recipe for disaster:

Code
IO.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 until run-time and thus represents a hidden flaw.

Tasks:

  1. Why can't we solve this issue by just changing the implementation?

  2. Solve the issue by modifying the method's signature requiring at least one value optionally being followed by additional values.

A:

  1. Due to its signature the max(...) method must return a value. If no argument is being passed there is no plausible way defining an empty list's maximum value.

  2. Changing its signature solves the issue:

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

Now at least one argument is being required. Violation yields a compile-time rather than just a run-time error:

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