2010-09-14 6 views
7

Estoy usando una biblioteca de terceros que devuelve un iterador sin formato, p. Ej.¿Atraviesa con seguridad un iterador sin formato en Java?

Iterator<?> children = element.getChildElements(); 

Conozco el tipo real, pero no confío necesariamente en que la lib de terceros se quede con él en el futuro. Hay dos (que se me ocurre) un tanto riesgo maneras de atravesar esta:

@SuppressWarnings("unchecked") 
Iterator<ActualObject> currentChildren = (Iterator<ActualObject>)currentElement.getChildElements(); 

o

Iterator<?> children = element.getChildElements(); 
while (null != children && children.hasNext()) { 
    ActualObject child = (ActualObject)children.next(); //Possible ClassCastException @ runtime 
    ... 
} 

La única forma "segura" Podría llegar a para atravesar este tipo de iterador es la siguiente:

Iterator<?> children = element.getChildElements(); 
while (null != children && children.hasNext()) { 
    Object obj = children.next(); 
    ActualObject child = null; 
    if (obj instanceof ActualObject) 
     child = (ActualObject)obj; 
    ... 
} 

Esto parece excesivamente prolijo. ¿Hay una forma mejor, pero igualmente "segura" de atravesar un iterador sin formato?

EDIT: me doy cuenta de que puedo capturar/registrar la excepción en un bloque else, estaba buscando (esperando) un equivalente en lenguaje Java de lo que ColinD ha mencionado a continuación.

+0

¿Qué desea que suceda si hay objetos devueltos por el iterador que son * no * instancias de 'ActualObject'? – pkaeding

+0

¿Qué se debe hacer si el tipo de hijo no es ActualObject? Si no necesita continuar, creo que capturar ClassCastException podría ser la forma más limpia de hacerlo. Puede registrar el tipo no coincidente y continuar. – Gangadhar

+0

@pkaeding & @Gangadhar - Yo lanzaría una excepción. –

Respuesta

7

Guava lo hace fácil con su método Iterators.filter(Iterator<?>, Class<T>). Devuelve un inmodificable Iterator<T> que, básicamente, sólo se salta todos los elementos del iterador teniendo en cuenta que no es una instancia del tipo T:

Iterator<ActualObject> children = Iterators.filter(element.getChildElements(), 
    ActualObject.class); 

es obvio que puede entonces atravesar el iterador resultante sin necesidad de echar a cada elemento ActualObject Y sin tener que preocuparse por ClassCastException.

+0

Gracias, eso es interesante, pero desafortunadamente usar Guava no es una opción para mí. –

+1

@Segphault: bueno, lea el código fuente y compruebe cómo lo hicieron. –

+0

Sospecho que hicieron lo mismo que el último ejemplo, pero simplemente lo extrajeron en un objeto contenedor. – pkaeding

2

La manera más fácil de manejarlo es simplemente echarlo y asegurarse de que, si el tipo cambia de lo que espera en el futuro, se lanzará una excepción y se le notificará. Deberá verificar que, sin importar cómo esté registrando excepciones, funcione y que la excepción llegue al archivo de registro. Existen excepciones para decirte que algo no es lo que esperas, permíteles hacer su trabajo.

Si omite de manera silenciosa elementos que no son del tipo esperado, entonces podría estar perdiendo los datos que necesita, eso no parece una buena solución para mí.

+2

I de acuerdo con la segunda parte –

2

Su última versión parece ser el camino a seguir pero supongo que podemos mejorar un poco:

Iterator<?> children = element.getChildElements(); 
// no null check needed. If an api that supposedly 
// returns an iterator actually returns null, it's a bad 
// API, don't use it 
while (children.hasNext()) { 
    Object obj = children.next(); 
    if (obj instanceof ActualObject) 
     doStuffWith((ActualObject)obj); 
    // we know it's of the right type so we might 
    // as well put the cast in the method call. 
} 

Por lo tanto, se reduce a esto:

Iterator<?> children = element.getChildElements(); 
while (children.hasNext()) { 
    Object obj = children.next(); 
    if (obj instanceof ActualObject) 
     doStuffWith((ActualObject)obj); 
} 

la que yo diría que ISN No está mal.

Editar:

No debe probablemente un bloque else debajo del bloque if, también. Algo a lo largo de las líneas de:

else{ 
    log.warn("Expected type: " + ActualObject.class + ", but got " + obj); 
} 
+0

Tiene razón acerca de la verificación nula, la eliminaré. ES una API incorrecta, en más formas que lo evidenciado por la pregunta. No puedo esperar para nunca volver a usarlo. –

1

Desde que suena como desea detener la ejecución y lanzar una excepción si se encuentra con un objeto devuelto por el iterador que no es una instancia de ActualObject, entonces me gustaría echarlo y tiene un bloque catch para lidiar con el posible ClassCastException.

Cuestiones relacionadas