2009-04-20 8 views
7

Supongamos que tengo un método que acepta un array y procesa cada elemento en él utilizando incorporado en for-each loop, como este de Java:¿Hay algún parámetro que pueda usar en Java que funcione con todos los bucles for-each?

public static void myFun(SomeClass[] arr) { 
    for (SomeClass sc : arr) { 
     // Stuff is processed here 
    } 
} 

Esto funciona muy bien, pero ahora yo quiero ser capaz de pasar el mismo método a List<SomeClass> en su lugar. ¿Estoy destinado a usar Collection.toArray(T []), o hay un parámetro que pueda usar para myFun() que acepte cualquier tipo que pueda usarse en una construcción para cada uno?

Para aclarar: Quiero una firma de método que acepte cualquier objeto iterable, ya sea una matriz primitiva o una Colección. Puedo escribir fácilmente dos métodos, uno envolviendo al otro, pero solo tengo curiosidad si hay una mejor manera.

+0

Lamentablemente, la respuesta es no, ya que las matrices no implementan Iterable. –

Respuesta

9

se recomienda usar Iterable, Collection o List como el tipo de parámetro.

IMO, las colecciones deben ser preferidas a las matrices de referencia. Si tiene una matriz Arrays.asList, la conversión es muy buena. Arrays.asList permite obtener y restablecer a través de la matriz, pero obviamente no modificaciones "estructurales" que cambiarían la longitud de la matriz.

myFun(Arrays.asList(arr)); 

Es posible que tenga que utilizar comodines en casos extremos/generales.

public static void myFun(Iterable<? extends SomeClass> somethings) { 
    for (SomeClass something : somethings) { 
     // something is processed here 
    } 
} 

Es de destacar que Collections.toArray y Arrays.asList trabajo de forma ligeramente diferente. asList mantiene la matriz original para respaldar la colección, por lo que los cambios en la colección se reflejarán en la matriz. Collections.toArray hace una copia (superficial) de los datos de la colección. Por lo general, hacer una copia es lo que querría si está devolviendo una matriz. Asimétricamente, si está pasando como un argumento, generalmente no copia (a menos que lo guarde como un campo).

+0

Acepto; para casos como este uso Iterable ya que impone la menor carga a los implementadores. Y aunque no funciona directamente con Object [], es trivial cerrar esto con Arrays.asList(). – erickson

+0

Sí. OTOH, la implementación podría concebir querer el tamaño de la colección antes de iterar, y la mayoría de los códigos aún usan Collection. –

+0

Dado que no parece haber una manera de evitar asList() o toArray(), estoy de acuerdo con esta lógica más; tiene sentido usar Iterable en lugar de Object [] si espero la entrada de ambos. –

5

Use Iterable. Para eso es para eso.

Como dijiste, Iterable no manejará las matrices.

No desea utilizar varios métodos que se complementen entre sí. Eso descarta Arrays.asList y Collection.toArray.

Así que la respuesta a su pregunta es no, no hay forma. Pero si puede usar Lists, ¿por qué alguna vez usaría matrices?

Todavía seguiría con Iterable aquí. Me gusta mejor que Collection porque en el pasado he tenido clases que implementaban Iterable pero no eran colecciones; esto les facilitó la recuperación lenta de valores según sea necesario, y pude usar el ciclo foreach en ellos.

+2

Si usa Iterable como parámetro, obtendrá errores de compilación cuando intente pasar matrices primitivas. –

+0

Ooh, no había pensado en eso. Déjame pensar un poco ... –

+0

¿Objeto [] Iterable? –

-3
public static void myFun(Collection<MyClass> collection) { 
    for (MyClass mc : collection) { 
     // Stuff is processed here 
    } 
} 
+0

MyCalss. –

+0

Esto no funcionará al pasar en una matriz –

3

no se puede, matrices de Java no implementa Iterable:

public static int sum(Iterable<Integer> elements) { 
    int s = 0; 

    for (int i : elements) { 
     s += i; 
    } 

    return s; 
} 

public static void main(String[] args) { 
    L1: System.out.println(sum(1,2,3)); 
    L2: System.out.println(sum(Arrays.asList(1,2,3))); 
    L3: System.out.println(sum(new int[] { 1,2,3 })); 
} 

esto da lugar a dos errores en tiempo de compilación en (L1 y L3); por lo que debe diseñar su método para aceptar una Iterable (colecciones) y/o una matriz, al menos un método debe realizar alguna conversión (a/de matriz)

Solución:

se pueden tratar con un adaptador:

public class ArrayIterator<T> implements Iterator<T> { 

    private final T[] array; 
    private int i; 

    public ArrayIterator(T[] anArray) { 
     array = anArray; 
     i = 0; 
    } 

    public boolean hasNext() { 
     return i < array.length; 
    } 

    public T next() { 
     return array[i++]; 
    } 

    public void remove() { 
     throw new UnsupportedOperationException(); 
    } 
} 

private static int sum(final Integer ... elements) { 
    return sum(new Iterable<Integer>() { 

     public Iterator<Integer> iterator() { 
      return new ArrayIterator<Integer>(elements); 
     } 
    }); 
} 

se debe prestar atención sólo cuando se trata de matrices primitivas; cuando se utiliza solamente objeto de referencia (su caso) ArrayIterator + clase anónima son frescas

creo que sirve

0

Hay una característica poco conocimiento de los genéricos de Java en Java 1.5+ donde se puede utilizar <? extends Subtype> en sus llamadas a métodos y constructores Puede usar <? extends Object>, y todo lo que tenga que ver con eso tendría acceso únicamente a los métodos en Object. Lo que quizá realmente quiere es algo más parecido a esto:

List<? extends MyCrustaceans> seaLife = new ArrayList<? extends MyCrustaceans>(); 
MyShrimp s = new MyShrimp("bubba"); 
seaLife.add(s); 
DoStuff(seaLife); 

... 

public static void DoStuff(List<? extends MyCrustaceans> seaLife) 
{ 
    for (MyCrustaceans c : seaLife) { 
     System.out.println(c); 
    } 
} 

Así que si usted tiene una clase base (como MyCrustaceans), puede utilizar cualquiera de los métodos de esa clase base en DoStuff (o de la clase Object, si su el parámetro es <? extends Object>). Hay una característica similar de <? super MyType>, donde acepta un parámetro que es un supertipo del tipo dado, en lugar de un subtipo. Hay algunas restricciones sobre lo que puede usar "extiende" y "súper" para de esta manera. Aquí hay un good place to find more info.

1

Respuesta corta: no, no hay una firma de método único que escriba con seguridad tanto un Iterable como una matriz. Obviamente, puedes aceptar Object, pero eso también sería un truco.

Respuesta larga-ish: Dado que la mayor for -loop se define efectivamente dos veces (una para las matrices y una vez para Iterable), tendrá que proporcionar dos métodos sobrecargados así:

public static void myFun(SomeClass[] array) { 
    for (SomeClass sc : array) { 
     doTheProcessing(sc); 
    } 
} 

public static void myFun(Iterable<? extends SomeClass> iterable) { 
    for (SomeClass sc : iterable) { 
     doTheProcessing(sc); 
    } 
} 

Aunque el la fuente de los dos métodos tiene exactamente el mismo aspecto, deberá definirla dos veces (a menos que, por supuesto, ajuste la matriz en su propio Iterable como se indica en @dfa).

+0

"Para aclarar: quiero una firma de método que acepte cualquier objeto iterable, ya sea una matriz primitiva o una Colección. Puedo escribir dos métodos muy fácilmente, uno envolviendo al otro, pero solo tengo curiosidad si hay una mejor manera ". –

+0

Ok, entonces no leí la pregunta lo suficientemente bien. Espero que este sea mejor. –

+1

Sí, realmente no hay otra respuesta. Todas las "respuestas" son solo soluciones o consejos. –

Cuestiones relacionadas