Varargs method parameter

Figure 404. 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 405. 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 406. Observations Slide presentation
  • Similar code in multiply overloaded methods.

  • Tedious: Each added argument requires adding another method.

Objective: Get rid of boilerplate code!


Figure 407. 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 408. 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 409. 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 410. Varargs: Generalizing arrays Slide presentation
  • Replace

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

    printInfo(String msg, int ... values)           

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

  • Must be the method's last argument.


Figure 412. Further reading on varargs Slide presentation

exercise No. 152

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. 153

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()'