JensGustavsson.se
Förstasidan | Arkiv | Artiklar | CodeCompanion | Länkar | Vem är Jens Gustavsson?
Förstasidan : januari 2005 : Article

Varargs i Java 1.5

I den här artikeln ska jag beskriva ännu en ny språkkonstruktion i Java 1.5. Konstruktionen heter "varargs" och går ut på att tillåta ett variabelt antal argument till metoder. Jag kan redan nu avslöja att jag tycker att varargs är en ganska onödig sak. Den kan få programkoden att bli tjusig i vissa situationer, men nyttan är på tok för liten för att motivera den nya syntaxen i språket. Varargs löser ett problem som inte finns. Eller som i varje fall är mycket litet. Men innan jag berättar mer om varför jag ogillar varargs kan det vara på sin plats att tala om vad det är för något.

Så här fungerar varags

Om en metod behöver kunna acceptera olika många parametrar vid olika anrop, kan man ju lösa det genom att låta metoden ta emot en array. Så här:

void foo(String[] indata) {
    // gör något
}

Man kan sedan anropa metoden med en array, och om man inte har någon array tillgänglig får man se till att skapa en. Det kan se ut så här:

foo(new String[] {"hej", "hopp", "hoffa"});

Hela idén med varargs är att förenkla skapandet av en sådan array vid anropet. Med Java 1.5 kan en metod deklareras så här:

void foo(String... indata) {
    // gör något
}

De tre punkterna talar om att metoden kan anropas med ett godtyckligt antal argument. Parametern "indata" blir en referens till en array av strängar, på precis samma sätt som i det tidigare exemplet. Den enda skillnaden i definitionen av metoden är alltså att hakparet bytts ut mot tre punkter. Anrop till metoden blir dock lite annorlunda. Nu går det att skicka in hur många strängar man vill utan att skapa någon array:

foo();
foo("hej");
foo("hej", "hopp", "hoffa");

Maximalt en parameter per metod får vara en varargs-parameter och den måste komma sist i parameterlistan. Och naturligtvis får andra typer än String användas.

Vad ska varargs användas till?

När är då varargs användbart? Man kan till exempel tänka sig en summeringsmetod som ska summera ett antal tal:

int summera(int... tal) {
    int resultat = 0;
    for(int i = 0; i < tal.length ; i++) {
        resultat += tal[i];
    }
    return resultat;
}

Nu kan man summera vilket antal tal som helst. Helfestligt. Verkligen. Eh, nej det är det inte. Problemet är att det sällan är intressant att skicka så värst många parametrar till en metod, även om man vill summera massor av tal. Har man massor av tal att summera så ligger de sannolikt i en array eller i en collection eller något liknande. Då är det listigare att ha en summeringsmetod som förväntar sig en array eller en collection eller något liknande som argument.

x = summera(a, b, c, d, e, f, g);  // ovanligt
y = summera(minTallista);  // vanligt

Om man nödvändigtvis vill kunna summera värdet av variablerna a till g som i exemplet, så är det naturligtvis möjligt utan varargs genom att skapa 10 överlagrade metoder som tar 1 till 10 parametrar. Fler variabler än 10 vill man sannolikt ändå inte rada upp på det sättet.

Varför finns varargs?

Det finns en enda anledning till att varargs har lagts till Java: avundsjuka på språket C. Där har en motsvarighet funnits sedan sjuttiotalet. Det man i Java-lägret egentligen varit avundsjuka på är funktionen "printf" i C och den funktionen kan hantera ett godtyckligt antal parametrar. Nu när varargs finns i Java har man kunnat lägga till en printf-metod i Javas klassbibliotek. Det den gör är att formatera text och variabelvärden på ett smidigt sätt. Så här kan den användas:

String förnamn = "Gunde";
String efternamn = "Svan";
int födelseår = 1962;
int nu = 2005;

System.out.print(förnamn + " " + efternamn + " är ungefär " + (nu - födelseår) + " år gammal.");
System.out.printf("%s %s är ungefär %d år gammal.", förnamn, efternamn, (nu - födelseår));

De två utskrifterna i exemplet blir identiska. Med printf stoppar man alltså in formateringsinformation med hjälp av procenttecken i en sträng, följt av ett antal parametrar som innehåller de värden som ska skrivas ut. Det är ganska trevligt faktiskt. Exakt hur formateringssträngarna fungerar beskrivs i dokumentationen till klassen java.util.Formatter. Beskrivningen är på ungefär 14 A4-sidor, så det finns en hel del formateringsvarianter att välja på.

Man kan tänka sig att Javas klassbibliotek ska innehålla många bra exempel på användning av varargs, men i hela klassbiblioteket används varargs bara av sammanlagt 25 metoder. 13 av dessa metoder är till för strängformatering som i exemplet ovan. Av resten rör de flesta reflection, där det är lite förvirrande att man nu hanterar parametrar i metanivån med samma syntax som parametrar i språket (carConstructor.newInstance("ABC123", type, 3500, true);). Men det kan jag leva med.

Vad göra med varargs?

Jag ser det som mycket ovanligt att behöva skapa egna metoder med en vararg-parameter. Och det är bara vettigt när man skapar programmeringsgränssnitt (API:er). Låt oss glädjas över trevlig textformatering med printf och hoppas att Sun tänker efter mer noga innan de i framtiden lägger till nya språkkonstruktioner i Java.