2009-06-01 7 views
5

Vorrei creare un metodo di inizializzazione per una classe Java che accetta 3 parametri:Metodo Java con parametri di dimensione della matrice applicata?

Employee[] method(String[] employeeNames, Integer[] employeeAges, float[] employeeSalaries) 
{ 
    Employee myEmployees[] = new Employee[SIZE];// dont know what size is 

    for (int count = 0; count < SIZE; count++) 
    { 
     myEmployees[count] = new Employee(employeeNames[count], employeeAges[count], employeeSalaries[count]); 
    } 
    return myEmployees; 
} 

Si può notare che questo codice è sbagliato. La variabile SIZE non è definita. Il mio problema è che vorrei passare in 3 array, ma vorrei sapere se posso garantire che i tre array siano TUTTI della stessa dimensione di array. In questo modo il ciclo for non fallirà, poiché il costruttore nel ciclo for usa tutti i parametri degli array.

Forse Java ha una funzione diversa che può imporre una soluzione al mio problema. Potrei accettare un altro parametro chiamato SIZE che verrà utilizzato nel ciclo for, ma questo non risolve il mio problema se i parametri 1 e 2 sono di dimensione 10 e il terzo parametro è un array di dimensioni 9.

Quindi, solo per riordinare in caso non fossi chiaro. Come posso far valere che i 3 argomenti sono tutti gli array che contengono esattamente lo stesso numero di elementi?

Utilizzando un parametro aggiuntivo che specifica le dimensioni dell'array non è molto elegante e il tipo di sporco. Inoltre, non risolve il problema, i parametri dell'array contengono array di dimensioni diverse.

risposta

16

Non è possibile imporlo in fase di compilazione. Fondamentalmente controlla che in fase di esecuzione, e un'eccezione se il vincolo non è soddisfatto:

Employee[] method(String[] employeeNames, 
        Integer[] employeeAges, 
        float[] employeeSalaries) 
{ 
    if (employeeNames == null 
     || employeeAges == null 
     || employeeSalaries == null) 
    { 
     throw new NullPointerException(); 
    } 
    int size = employeeNames.length; 
    if (employeesAges.length != size || employeeSalaries.length != size) 
    { 
     throw new IllegalArgumentException 
      ("Names/ages/salaries must be the same size"); 
    } 
    ... 
} 
+0

Grazie Jon, risposta eccellente! –

+2

Questo è un buon esempio di ciò che considero il modo sbagliato di utilizzare NullPointerException. Effettuerei un controllo individuale per ciascuno dei parametri passati if (employeeNames == null) { throw new IllegalArgumentException ("employeeNames == null"); } Ciò rende lo stacktrace molto più utile per diagnosticare il problema. –

+0

Penso che sia altrettanto accettabile lanciare un NPE in questo caso (mentre nessuno sarebbe in disaccordo con il lancio di un IAE); ma forse come un compromesso in questa discussione/controversia sarebbe meglio includere un messaggio con l'NPE. –

2

Poiché gli array vengono passati non vengono generati fino runtime, non è possibile impedire il metodo chiamata dal completamento in base alle caratteristiche dell'array passato come controllo in fase di compilazione.

Come ha detto Jon Skeet, l'unico modo per indicare un problema è lanciare un IllegalArgumentException o simile in fase di esecuzione per arrestare l'elaborazione quando il metodo viene chiamato con i parametri errati.

In ogni caso, la documentazione deve chiaramente indicare le aspettative e il "contratto" per l'utilizzo del metodo - il passaggio di tre array che hanno le stesse lunghezze. Probabilmente sarebbe una buona idea annotarlo nei Javadoc per il metodo.

0

Un modo di aggirare il problema è quello di creare un costruttore, per esempio, EmployeeArrayBuilder,

public class EmployeeArrayBuilder { 
    private Integer arraySize = null; 
    private String[] employeeNames; 
    public EmployeeArrayBuilder addName(String[] employeeNames) { 
     if (arraySize == null) { 
     arraySize = employeeNames.length; 
     } else if (arraySize != employeeNames.length) { 
     throw new IllegalArgumentException("employeeNames needs to be " + arraySize + " in length"); 
     } 
     this.employeeNames = employeeNames; 
     return this; 
    } 
    public EmployeeArrayBuilder addSalaries(float[] employeeSalaries) {/* similar to above */} 
    public EmployeeArrayBuilder addAges(Integer[] employeeAges) {/* similar */} 
    public Employee[] build() { 
     // here, you can do what you needed to do in the constructor in question, and be sure that the members are correctly sized. 
     Employee myEmployees[] = new Employee[arraySize ];// dont know what size is    
     for (int count = 0; count < arraySize ; count++) { 
      myEmployees[count] = new Employee(employeeNames[count], employeeAges[count], employeeSalaries[count]); 
     } 
     return myEmployees; 
    } 
} 
+0

Non penso che un costruttore è appropriato perché non c'è nulla nell'API che suggerisca che età, nomi e stipendi siano tutti obbligatori.Il costruttore è appropriato quando è possibile avere argomenti facoltativi.È anche piuttosto complesso rispetto alla risposta di Jon Skeet. –

+0

@Ken Liu: entrambi risolve lo stesso problema - ho postato questo perché l'altra soluzione è già pubblicata quindi perché duplicare? e questa è un'alternativa che merita alcune considerazioni. Infatti non c'è nulla nell'API che suggerisca che questi siano argomenti necessari, ma che non toglie nulla il modello del costruttore. – Chii