SCJP Study Guide:
Declarations, Initialization and Scoping


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents
XyzWs SCJP Study Guide: Varargs

Varargs

 

What is Varargs?

Varargs is a facility available in native code for C and C++ programmers, where a function can take a variable number of arguments, this is usually indicated by an ellipsis at the end of its parameter list.

In Java 5.0, it adds convenience of using variable arity parameters, known less formally as varargs. One particularly nice feature about varargs is that a variable-length argument can be take from zero to n arguments.

 

Without much programming effort, the varargs feature allows you to define methods that accept a variable number of arguments

Simple Example

In past Java releases, a method that took an arbitrary number of values required you to create an array and put the values into the array prior to invoking the method.

class VarGreeter {
  public static void printGreeting(String[] names) {
    if (names == null || names.length == 0) {
      return;
    }
    for (int len =0; len < names.length; len++) {
         System.out.println("Hello " + names[len] + ". ");
    }
  }

  public static void main(String[] args) {
    printGreeting("Paul", "Sue");
  }
}

The three periods after the final parameter's type indicate that the final argument may be passed as an array or as a sequence of arguments.

It is still true that multiple arguments must be passed in an array, but the varargs feature automates and hides the process. Furthermore, it is upward compatible with preexisting APIs.

You might use varargs to allow printing one to many greetings to a collection that you have defined by using a single printGreeting method call. Suppose you need a method that writes any number of records to the console. Using varargs, you can make any of the following method calls:

class VarGreeter {
  public static void printGreeting(String... names) {
    for (String s: names) {
         System.out.println("Hello " + s + ". ");
    }
  }

  public static void main(String[] args) {
    printGreeting("Paul");
    printGreeting("Paul", "Sue");
    printGreeting("Paul", "Sue", "Mark", "Joe");
  }
}

First, the names argument is defined as type String.... This indicates to the compiler that calling code can pass a variable number of String parameters. For all other intents and purposes, however, String... equates to a String array (String[]).

At compile time a vararg is converted to an array. The varargs facility is just implicit syntax for creating and passing arrays, an array can be passed directly. In such case (directly passing a typed array), the compiler will simply pass the array unmodified.

class VarGreeter {
  public static void printGreeting(String... names) {
    for (String s: names) {
         System.out.println("Hello " + s + ". ");
    }
  }

  public static void main(String[] args) {
    printGreeting(args);
  }
}

 

Rules for Vararg Methods

  • To declare a method using a var-arg parameter, the var-arg parameter's syntax is "type... name".
  • A vararg method can have one and only one variable arity parameter in its method's signature.
  • The variable argument parameter doesn't have to be the only argument. Only the last argument to the method can be declared as accepting a variable list. You can't put the variable-length argument first (except that there is only one variable arity parameter).

 

Access Vararg Argument

The vararg argument is accessed just like an array. Normally, you would do something more like the following in an enhanced for loop:

  for (Type arg: args) {
    ...
  }

or

  for (int n = 0; ((args != null) && (n < args.length)); n++) {
    ...
  }

This would allow you to process one element at a time.

 

Varargs and Overloading

The following example illustrates how the most specific overloaded method is chosen for a method call.  For example,

import static java.lang.System.out;
class VarargsOverloading {
  public void operation(String str) { 
	String signature = "(String)"; 
	out.println(str + "=> " + signature); } 
  
  public void operation(String str, int m) { 
    String signature = "(String, int)"; 
	out.println(str + "=> " + signature); }
  
  public void operation(String str, int m, int n) { 
    String signature = "(String, int, int)"; 
	out.println(str + "=> " + signature); }

  public void operation(String str, Integer... data) { 
    String signature = "(String, Integer[])"; 
	out.println(str + "= > " + signature); } 
			
  public void operation(String str, Number... data) {
    String signature = "(String, Number[])"; 
	out.println(str +" = > " + signature); }
  
  public void operation(String str, Object... data) { 
    String signature = "(String, Object[])"; 
	out.println(str+ " = > " + signature);
  }

  public static void main(String[] args) {
    VarargsOverloading ref = new VarargsOverloading();
    ref.operation("(String)");
    ref.operation("(String, int)", 10);
    ref.operation("(String, Integer)", new Integer(10));
    ref.operation("(String, int, byte)", 10, (byte)20);
    ref.operation("(String, int, int)", 10, 20);
    ref.operation("(String, int, long)", 10, 20L);
    ref.operation("(String, int, int)", 10, 20, 30);
    ref.operation("(String, int, double)", 10, 20.0);
    ref.operation("(String, int, String)", 10, "what?");
    ref.operation("(String, boolean)", false);
  }
}

output results are

(String) => (String)
(String, int) = > (String, int) 
(String, Integer) = >(String, int) 
(String, int, byte) => (String, int, int) 
(String, int, int)=> (String, int, int) 
(String, int, long)= > (String, Number[]) 
(String, int, int) = > (String, Integer[]) 
(String, int, double) => (String, Number[])
(String, int, String) => (String, Object[]) 
(String, boolean) = > (String, Object[])

 

Varargs and Overriding

Overriding of varargs methods does not present any suprises as long as criteria for overriding is satisfied.

import static 
java.lang.System.out; 
public class OneSuperclass {
  public int doIt(String str, Integer... data) 
    throws java.io.EOFException, java.io.FileNotFoundException {
    // (1) String signature = "(String, Integer[])"; 
	out.println(str +" = > " + signature);
	return 1; }

  public void doIt(String str, Number... data) { 
   // (2) String signature = "(String, Number[])"; 
    out.println(str + " = > " + signature);}
}

Overriding Case I:

import static java.lang.System.out;
public class OneSubclass extends OneSuperclass {

  public int doIt(String str, Integer[] data) 
           throws java.io.FileNotFoundException {
    String signature = "(String, Integer[])"; 
    out.println("Overridden: "+ str + " = > " + signature);
    return 0; 
  }
  
  public void doIt(String str, Object... data) { 
    // Overloading String signature = "(String, Object[])"; 
    out.println(str + " = > " + signature);
  }

  public static void main(String[] args) throws Exception {
    OneSubclass ref = new OneSubclass();
    ref.doIt("(String)");
    ref.doIt("(String, int)", 10);
    ref.doIt("(String, Integer)", new Integer(10));
    ref.doIt("(String, int, byte)", 10, (byte)20);
    ref.doIt("(String, int, int)", 10, 20);
    ref.doIt("(String, int, long)", 10, 20L);
    ref.doIt("(String, int, int)", 10, 20, 30);
    ref.doIt("(String, int, double)", 10, 20.0);
    ref.doIt("(String, int, String)", 10, "what?");
    ref.doIt("(String, boolean)", false);
  }

}

output results are

(String) => (String, 
Number[]) 
(String, int) =>(String, Number[]) 
(String, Integer) =>(String, Number[])
(String, int, byte) => (String, Number[]) 
(String, int, int) => (String, Number[])
(String, int, long) = > (String, Number[]) 
(String, int, int, int) = > (String, Number[])
(String, int, double) => (String, Number[])
(String, int, String) => (String, Object[])
(String, boolean) = > (String, Object[])

Overriding Case II:

import static java.lang.System.out;
public class OneSubclass extends OneSuperclass {

  public int doIt(String str, Integer... data) // Overriding
           throws java.io.FileNotFoundException  {
    String signature = "(String, Integer[])"; 
    out.println("Overridden: " + str + " = > " + signature);
    return 0; 
  }

  public void doIt(String str, Object... data) { 
  // Overloading String signature = "(String, Object[])"; 
    out.println(str + " = > " + signature);
  }

  public static void main(String[] args) throws Exception {
    OneSubclass ref = new OneSubclass();
    ref.doIt("(String)");
    ref.doIt("(String, int)", 10);
    ref.doIt("(String, Integer)", new Integer(10));
    ref.doIt("(String, int, byte)", 10, (byte)20);
    ref.doIt("(String, int, int)", 10, 20);
    ref.doIt("(String, int, long)", 10, 20L);
    ref.doIt("(String, int, int)", 10, 20, 30);
    ref.doIt("(String, int, double)", 10, 20.0);
    ref.doIt("(String, int, String)", 10, "what?");
    ref.doIt("(String, boolean)", false);
  }

}

output results are

Overridden: (String) => (String, Integer[]) 
Overridden: (String, int) => (String, Integer[]) 
Overridden: (String, Integer) => (String, Integer[])
(String, int, byte) => (String, Number[]) 
Overridden: (String, int, int) => (String, Integer[]) 
(String, int, long) = > (String, Number[]) 
Overridden: (String, int, int, int) = > (String, Integer[]) 
(String, int, double) => (String, Number[])
(String, int, String) => (String, Object[]) 
(String, boolean) = > (String, Object[])

 


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |