2012-02-16 16 views
5

Il seguente Python snipped fa esattamente quello che voglio dire:Come posso espandere gli argomenti in Java?

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

def function(a, b, c): 
    print("%i :: %s :: %f" % (a,b,c)) 

a = 1 
b = "abc" 
c = 1.0 

function(a, b, c) 

list = [a, b, c] 

# This is what I am searching for in Java 
function(*(list)) 

Così ho una struttura della lista-like e non so quanti argomenti che ha, ma so che ha il giusto numero di argomenti con il giusto tipo e formato. E voglio passarli a un metodo. Quindi devo "espandere" questi argomenti. Qualcuno sa come farlo in Java?

+0

Forse stai cercando [per] (http://stackoverflow.com/questions/766559/when-do-you-use-varargs-in-java) [varargs] (http://docs.oracle.com /javase/1.5.0/docs/guide/language/varargs.html)? –

+0

Definisci "espandi"? Dal tuo esempio non è chiaro cosa significhi. – Tudor

+0

Se si desidera utilizzare qualcosa come l'operatore '%', è possibile utilizzare la classe 'Formatter' come nella mia risposta di seguito. –

risposta

5

Java non ha questa possibilità, dal momento che come linguaggio staticamente, fortemente tipizzato è raro che un metodo per prendere un insieme di valori di tipo uniforme, che potrebbero tutti essere conservato in un oggetto composito (array, lista, ecc .). Python non ha questo problema perché tutto è digitato in modo dinamico. Puoi farlo in Java definendo un metodo helper che prende un singolo oggetto tenendo tutti i parametri, quindi li espande in una chiamata al metodo reale.

Spero che questo aiuti!

1

Non è possibile. In Java, i parametri del metodo vengono controllati in fase di compilazione e poiché il contenuto dell'array viene definito solo in fase di esecuzione, questo controllo sarebbe impossibile.

La soluzione più vicina è quella di disporre di un metodo che assuma un array come parametro e, infine, di espandere gli argomenti per effettuare una chiamata al metodo di destinazione.

2

Si potrebbe dichiarare parametri opzionali con Object... tale che si può passare un numero arbitrario di argomenti e poi gettato ciascuno di loro per il tipo di richiesta:

public void method1(String p1, Integer p2) { 
} 

public void method2(Object... params) { 
    method1((String)params[0], (Integer)params[1]; 
} 

È possibile chiamare method2 come:

method2("abc", 1); 

Ovviamente, questo esempio è un po 'ridondante, perché è possibile chiamare direttamente method1, ma non è quello che volevo illustrare. :)

0

Si può fare questo:

import java.util.Formatter; 

// ... 

StringBuilder target = new StringBuilder(); 
Formatter formatter = new Formatter(target); 

List<Integer> integers = new ArrayList<Integer>(); 
integers.add(1); 
integers.add(2); 
integers.add(3); 

formatter.format("%d %d %d", integers.toArray()); 
System.out.println(target.toString()); 

Edit:Javadoc for java.util.Formatter

0

Penso che questo fa la stessa cosa come il codice iniziale con una sintassi simile ...

public class MultiArgs { 

    public static void main(String[] args) { 
     int a = 1; 
     String b = "abc"; 
     double c = 1.0; 
     List<?> list = Arrays.asList(a, b, c); 

     System.out.println(function(a, b, c)); // 1 :: abc :: 1.000000 
     System.out.println(function(list.toArray())); // 1 :: abc :: 1.000000 
    } 

    private static <T extends Object> String function(T... objects) { 
     return String.format("%d :: %s :: %f", objects); 
    } 
} 
0

Non è raccomandato (come le note di risposta di templatetypedef, questo è uno schema molto raro per un linguaggio fortemente tipizzato), ma tu Fai quello che vuoi usando il riflesso.

SomeType foo = //obtained from elsewhere 
List<?> args = //obtained from somewhere else 

//this bit obtains the method handle 
Method theMethod = null; 
for (Method m : foo.getClass().getMethods()) { 
    if (m.getName().equals("theMethodIWant") { 
     theMethod = m; 
     break; 
    } 
} 

theMethod.invoke(foo, args.toArray()); //this is the line that does the magic 

Alcuni avvertimenti abbastanza gravi:

  • Riflessione possono avere un impatto significativo delle prestazioni rispetto ad una chiamata diretta - molto di più che in un linguaggio dinamico come Python. Questo può o non può importare. In caso di dubbio, misura.

  • Il blocco che ottiene un handle metodo comporta un puntatore nullo se un metodo con questo nome non viene trovato

  • La lista degli argomenti deve avere esattamente il giusto numero di argomenti, con il tipo giusto . Sei responsabile di verificarlo da qualche altra parte. Questo è più difficile di quanto sarebbe in un linguaggio dinamico, in quanto il runtime farà molto meno (se c'è) tipo di coercizione per te.

  • method.invoke() può lanciare una serie di eccezioni (IllegalAccessException, IllegalArgumentException, InvocationTargetException, ecc) che questo esempio ignora. Dovrai individuare e gestire questi errori in modo appropriato

  • se il metodo chiamato non è pubblico, dovrai fare ancora più lavoro di questo per chiamarlo.

  • questo esempio non tenta nemmeno di affrontare il caso in cui si dispone di un metodo sovraccarico. Due metodi denominati "theMethodIWant" con diversi elenchi di argomenti richiedono un approccio diverso per ottenere l'handle del metodo.

Tutto sommato, consiglierei di non utilizzare il riflesso se possibile.

Problemi correlati