2009-04-20 21 views
176

Ho paura dei vararg. Non so per cosa usarli.Quando si usano vararg in Java?

Inoltre, è pericoloso lasciare che le persone passino il maggior numero di argomenti che vogliono.

Qual è un esempio di contesto che sarebbe un buon posto per usarli?

+2

Non vedo perché sarebbe" pericoloso ".Non è più pericoloso di avere un metodo chiamato un gran numero di volte con argomenti diversi. Hai dubbi con lo stack? Allora non dovresti, perché varargs è mappato agli array che vengono passati per riferimento – jfpoilpret

+63

Volevo solo inserire la suoneria: non c'è niente di sbagliato nell'evitare le caratteristiche del linguaggio con cui non sei (ancora) completamente a tuo agio. Molto meglio che usare le funzioni che non capisci!;) – Steven

+2

È normale temere lo sconosciuto. Per ulteriori informazioni, leggi qui le vararg http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html. Vedrai che i vararg non hanno nulla da temere I Vararg sono utili: sapere come usare varargs ti dà la possibilità di scrivere metodi come [PrintStream.format] ("http://docs.oracle.com/javase/7/docs/api/java/io/PrintStr eam.html # printf (java.lang.String, java.lang.Object ...) ") :). – Willmore

risposta

144

varargs sono utili per qualsiasi metodo che deve affrontare un numero indeterminato di oggetti. Un buon esempio è String.format. La stringa di formato può accettare qualsiasi numero di parametri, quindi è necessario un meccanismo per passare un numero qualsiasi di oggetti.

String.format("This is an integer: %d", myInt); 
String.format("This is an integer: %d and a string: %s", myInt, myString); 
+4

Un parametro array può anche ricevere un numero indeterminato di oggetti, ma un parametro varargs consente maggiore flessibilità e praticità al punto di chiamata. Puoi scrivere codice per costruire un array e passarlo, oppure puoi lasciare che Java lo faccia per te quando scegli di riceverlo in un parametro varargs. – H2ONaCl

1

Uso spesso vararg per i costruttori che possono prendere una sorta di oggetto filtro. Ad esempio, gran parte del nostro sistema basato su Hadoop si basa su un Mapper che gestisce la serializzazione e la deserializzazione di elementi su JSON e applica un numero di processori che ciascuno prende un elemento di contenuto e lo modifica e lo restituisce, oppure restituisce null rifiutare.

77

Una buona regola sarebbe:

"Uso varargs per qualsiasi metodo (o costruttore) che richiede un array di T (qualsiasi tipo T può essere) come input".

Ciò renderà le chiamate a questi metodi più facili (non è necessario fare new T[]{...}).

È possibile estendere questa regola per includere metodi con un argomento List<T>, a condizione che questo argomento sia solo per l'input (ovvero, l'elenco non viene modificato dal metodo).

Inoltre, vorrei astenermi dall'usare f(Object... args) perché scivola verso un modo di programmazione con API poco chiare.

In termini di esempi, che hanno consumata nello DesignGridLayout, dove posso aggiungere diverse JComponent s in una chiamata:

layout.row().grid(new JLabel("Label")).add(field1, field2, field3); 

Nel codice precedente il metodo add() è definito come add(JComponent... components).

Infine, l'implementazione di tali metodi deve occuparsi del fatto che possa essere chiamato con un vararg vuoto! Se si vuole imporre almeno un argomento, quindi è necessario utilizzare un brutto scherzo come ad esempio:

void f(T arg1, T... args) {...} 

Considero questo trucco brutto perché l'implementazione del metodo sarà meno semplice che avere solo T... args nelle sue argomentazioni elenco.

Si spera che questo aiuti a chiarire il punto sui vararg.

+1

Hai considerato di aggiungere un controllo di precondizione 'if (args.length == 0) lancia una nuova RuntimeException (" foo ");' invece?(Dato che il chiamante stava violando il contratto) –

+23

Bene, lo scopo di una buona API è prevenire l'uso improprio il prima possibile, quindi al momento della compilazione quando è possibile, da qui il suggerimento per 'void f (T arg1, T ... args) 'che garantisce sempre che non venga mai chiamato senza argomento, senza bisogno di attendere il runtime. – jfpoilpret

+0

Penso che la maggior parte delle volte una chiamata a una funzione solo varargs senza argomenti equivale solo a non fare nulla. Il punto è che non fornire argomenti a una funzione varargs molto probabilmente non causerà un danno considerevole. – WorldSEnder

5

Ho una paura varargs legati anche:

Se il chiamante passa in un array esplicito al metodo (al contrario di parametri multipli), si riceverà un riferimento condiviso per tale matrice.

Se è necessario archiviare questo array internamente, si consiglia di clonarlo prima per evitare che il chiamante possa modificarlo in un secondo momento.

Object[] args = new Object[] { 1, 2, 3} ; 

varArgMethod(args); // not varArgMethod(1,2,3); 

args[2] = "something else"; // this could have unexpected side-effects 

Anche se questo non è realmente differente dalla passare in qualsiasi tipo di oggetto il cui stato potrebbe cambiare in seguito, poiché la matrice è generalmente (in caso di una chiamata con argomenti multipli invece di un array) una fresca creato da il compilatore internamente che puoi tranquillamente usare, questo è certamente un comportamento inaspettato.

+1

Corretto, ma questo esempio sembra un po 'inverosimile. È probabile che la gente userà la tua API in questo modo? – jfpoilpret

+2

Non si sa mai ... E soprattutto quando il numero di argomenti non è hard-coded sul lato chiamante, ma anche raccolto say in una lista in un ciclo, passare in un array non è poi così raro. – Thilo

+5

Penso che il tuo esempio di caso d'uso sia, in generale, non improbabile. Si potrebbe obiettare che la tua API non dovrebbe usare l'array di input in questo modo, e se lo fa, deve documentarlo. –

33

Uso spesso varargs per l'output nei log a scopo di debug.

Praticamente ogni classe nella mia app ha un metodo debugPrint():

private void debugPrint(Object... msg) { 
    for (Object item : msg) System.out.print(item); 
    System.out.println(); 
} 

Poi, all'interno dei metodi della classe, ho chiamate come il seguente:

debugPrint("for assignment ", hwId, ", student ", studentId, ", question ", 
    serialNo, ", the grade is ", grade); 

Quando ho' Soddisfatto che il mio codice funzioni, commento il codice nel metodo debugPrint() in modo che i registri non contengano troppe informazioni estranee e indesiderate, ma posso lasciare le singole chiamate a debugPrint() senza commento. Successivamente, se trovo un bug, annullo semplicemente il codice debugPrint() e tutte le mie chiamate a debugPrint() vengono riattivate.

Naturalmente, potrei altrettanto facilmente rifuggono varargs e procedere come segue invece:

private void debugPrint(String msg) { 
    System.out.println(msg); 
} 

debugPrint("for assignment " + hwId + ", student " + studentId + ", question " 
    + serialNo + ", the grade is " + grade); 

Tuttavia, in questo caso, quando io commento il codice debugPrint(), il server deve ancora passare attraverso il problema di concatenare tutte le variabili in ogni chiamata a debugPrint(), anche se non viene fatto nulla con la stringa risultante. Se uso varargs, tuttavia, il server deve solo inserirli in un array prima che si accorga che non ne ha bisogno. Un sacco di tempo è salvato.

+3

È possibile implementare un metodo di debug nella superclasse per stampare qualsiasi oggetto utilizzando la riflessione. –

11

Varargs può essere utilizzato quando non si è sicuri del numero di argomenti da passare in un metodo. Crea una serie di parametri di lunghezza non specificata in background e tale parametro può essere trattato come una matrice in runtime.

Se abbiamo un metodo che è sovraccarico per accettare un numero diverso di parametri, invece di sovraccaricare il metodo diverse volte, possiamo semplicemente usare il concetto di vararg.

Anche quando il tipo di parametri sta per variare, l'uso di "Object ... test" semplifica notevolmente il codice.

Ad esempio:

public int calculate(int...list) { 
    int sum = 0; 
    for (int item : list) { 
     sum += item; 
    } 
    return sum; 
} 

Qui indirettamente un array di tipo int (elenco) viene passato come parametro e viene trattato come un array nel codice.

Per una migliore comprensione segui questo link (che mi ha aiutato molto nella comprensione di questo concetto in modo chiaro): http://www.javadb.com/using-varargs-in-java

P.S: Anche io avevo paura di usare varargs quando non ho KNW circa esso. Ma ora ci sono abituato. Come si dice: "Ci aggrappiamo al conosciuto, paura dell'ignoto", quindi basta usarlo il più possibile e anche tu inizierai a piacergli :)

+4

C# L'equivalente di varargs è "params". Fa anche la stessa cosa e accetta un numero variabile di parametri. Vedere questo per una migliore comprensione: http://www.dotnetperls.com/params – Sarvan

8

Varargs è la funzionalità aggiunta in java versione 1.5 .

Perché utilizzare questo?

  1. E se non si conosce il numero di argomenti da passare per un metodo?
  2. E se si desidera passare un numero illimitato di argomenti a un metodo?

Come funziona?

Crea una matrice con gli argomenti specificati & passa la matrice al metodo.

Esempio:

public class Solution { 



    public static void main(String[] args) { 
     add(5,7); 
     add(5,7,9); 
    } 

    public static void add(int... s){ 
     System.out.println(s.length); 
     int sum=0; 
     for(int num:s) 
      sum=sum+num; 
     System.out.println("sum is "+sum); 
    } 

} 

uscita:

somma è 12

somma è 21

1

In Java doc di Var-args è del tutto evidente l'utilizzo di args var:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html

sull'uso che dice:

"Così, quando si dovrebbe usare varargs? Come cliente, dovresti approfittarne ogni volta che l'API li offre. Gli usi importanti nelle API di base includono la riflessione, la formattazione dei messaggi e la nuova funzione printf. Come progettista di API, dovresti usarli con parsimonia, solo quando il vantaggio è davvero avvincente. In generale, non si dovrebbe sovraccaricare un metodo varargs, o sarà difficile per i programmatori capire quale sovraccarico viene chiamato. "

Problemi correlati