Varargs op Java

1. Inleiding

Varargs werden geïntroduceerd in Java 5 en bieden een korte hand voor methoden die een willekeurig aantal parameters van één type ondersteunen.

In dit artikel zullen we zien hoe we deze Java-kernfunctie kunnen gebruiken.

2. Voorheen Varargs

Vóór Java 5 moesten we, telkens als we een willekeurig aantal argumenten wilden doorgeven, alle argumenten in een array doorgeven of N-methoden implementeren (één voor elke extra parameter):

public String format () {...} public String format (String waarde) {...} public String format (String waarde1, String waarde2) {...}

3. Gebruik van Varargs

Varargs help ons het schrijven van standaardcode te voorkomen door de nieuwe syntaxis te introduceren die automatisch een willekeurig aantal parameters kan verwerken - met behulp van een array onder de motorkap.

We kunnen ze definiëren met behulp van een standaardtypedeclaratie, gevolgd door een ellips:

public String formatWithVarArgs (String ... waarden) {// ...}

En nu kunnen we onze methode aanroepen met een willekeurig aantal argumenten, zoals:

formatWithVarArgs (); formatWithVarArgs ("a", "b", "c", "d");

Zoals eerder gezegd, varargs zijn arrays, dus we moeten ermee werken, net zoals we met een normale array zouden werken.

4. Regels

Varargs zijn eenvoudig te gebruiken. Maar er zijn een paar regels waar we rekening mee moeten houden:

  • Elke methode kan er maar één hebben varargs parameter
  • De varargs argument moet de laatste parameter zijn

5. Hoop vervuiling

Gebruik makend van varargs kan leiden tot zogenaamde Heap Pollution. Overweeg dit om de hoopvervuiling beter te begrijpen varargs methode:

statische String firstOfFirst (Lijst ... strings) {List ints = Collections.singletonList (42); Object [] objecten = strings; objecten [0] = ints; // Heap vervuilingsretourstrings [0] .get (0); // ClassCastException}

Als we deze vreemde methode in een test noemen:

String one = firstOfFirst (Arrays.asList ("één", "twee"), Collections.emptyList ()); assertEquals ("een", een);

We zouden een ClassCastException ook al hebben we hier niet eens expliciete typen casts gebruikt:

java.lang.ClassCastException: class java.lang.Integer kan niet worden gecast naar class java.lang.String

5.1. Veilig gebruik

Elke keer dat we gebruiken varargs, maakt de Java-compiler een array om de opgegeven parameters vast te houden. In dit geval maakt de compiler een array met componenten van het generieke type om de argumenten vast te houden.

Wanneer we gebruiken varargs met generieke typen, omdat er een potentieel risico is op een fatale runtime-uitzondering, waarschuwt de Java-compiler ons voor een mogelijk onveilige varargs gebruik:

waarschuwing: [varargs] Mogelijke hoop vervuiling door geparametriseerde vararg type T

De varargs gebruik is alleen veilig als:

  • We slaan niets op in de impliciet gemaakte array. In dit voorbeeld hebben we een Lijst in die reeks
  • We laten een verwijzing naar de gegenereerde array niet ontsnappen aan de methode (hierover later meer)

Als we zeker weten dat de methode zelf de varargs veilig gebruikt, kunnen we @BuienRadarNL om de waarschuwing te onderdrukken.

Simpel gezegd, de varargs gebruik is veilig als we ze gebruiken om een ​​variabel aantal argumenten over te dragen van de beller naar de methode en niets meer!

5.2. Ontsnappen Varargs Referentie

Laten we eens kijken naar een ander onveilig gebruik van varargs:

statische T [] toArray (T ... arguments) {return arguments; }

In eerste instantie lijkt het erop dat de toArray methode is volkomen onschadelijk. Omdat het de array varargs echter laat ontsnappen naar de beller, is het in strijd met de tweede regel van safe varargs.

Laten we, om te zien hoe gevaarlijk deze methode kan zijn, deze in een andere methode gebruiken:

statische T [] returnAsIs (T a, T b) {return toArray (a, b); }

Als we deze methode dan noemen:

String [] args = returnAsIs ("Een", "Twee");

We zouden opnieuw een ClassCastException. Dit is wat er gebeurt als we de returnAsIs methode:

  • Slagen een en b naar de toArray methode, moet Java een array maken
  • Sinds de Voorwerp[] kan items van elk type bevatten, de compiler maakt er een aan
  • De toArray methode geeft het gegeven terug Voorwerp[] aan de beller
  • Omdat de call-site een Draad[], de compiler probeert het Voorwerp[] aan de verwachte Draad[], vandaar de ClassCastException

Voor een meer gedetailleerde bespreking van hoopvervuiling, wordt het ten zeerste aanbevolen om item 32 van Effective Java door Joshua Bloch te lezen.

6. Conclusie

Varargs kan veel boilerplate laten verdwijnen in Java.

En, dankzij hun impliciete autoboxing naar en van Matrix, zij spelen een rol bij het toekomstbestendig maken van onze code.

Zoals altijd zijn alle codevoorbeelden uit dit artikel beschikbaar in onze GitHub-repository.