Implicaciones de eficiencia de clase anónimas de Java

¿Hay alguna diferencia en la eficiencia (por ejemplo, el tiempo de ejecución, el tamaño del código, etc.) entre estas dos formas de hacer las cosas?

A continuación hay ejemplos artificiales que crean objetos y no hacen nada, pero mis escenarios reales pueden estar creando nuevos hilos, oyentes, etc. Suponga que las siguientes piezas de código ocurren en un bucle para que pueda hacer una diferencia.

Usando objetos anónimos:

void doSomething() { for (/* Assume some loop */) { final Object obj1, obj2; // some free variables IWorker anonymousWorker = new IWorker() { doWork() { // do things that refer to obj1 and obj2 } }; } } 

Definir una clase primero:

 void doSomething() { for (/* Assume some loop */) { Object obj1, obj2; IWorker worker = new Worker(obj1, obj2); } } static class Worker implements IWorker { private Object obj1, obj2; public CustomObject(Object obj1, Object obj2) {/* blah blah */} @Override public void doWork() {} }; 

La única diferencia práctica entre las clases anónimas y las clases de nivel superior es que las clases anónimas tendrán una referencia implícita a la clase externa.

Esto no se manifestará en el rendimiento, pero le afectará si alguna vez serializa estas clases.

Debe haber poca o ninguna diferencia de rendimiento. Si hay una diferencia, estará en un nivel en el que no vale la pena preocuparse.

OMI, debe centrarse en escribir código que sea legible y mantenible, e ignorar los problemas de rendimiento “micro” hasta que tenga pruebas claras de que son significativos … en función del perfil de la aplicación.

(Para el registro, cuando una clase interna anónima se refiere a una final en un ámbito adjunto, esto se implementa en el nivel de bytecode por medio de argumentos de constructor ocultos y atributos de instancia ocultos. Los bytecodes serán casi los mismos que los bytecodes que obtiene de su otra implementación).

Es importante darse cuenta de que las clases anónimas siguen siendo clases conocidas y comstackdas por completo en tiempo de comstackción. El hecho de que, por ejemplo, esté definiendo un cuerpo de clase anónimo, quizás con muchos métodos y campos, etc. dentro de un bucle, no significa que el tiempo de ejecución tenga que comstackr ese tipo en cada iteración.

Por lo tanto, cualquier diferencia en el rendimiento entre los dos enfoques es insignificante. Los factores importantes a considerar son cosas como legibilidad, reutilización, capacidad de prueba, etc.

De hecho, he notado un impacto significativo en el rendimiento al crear instancias de muchas instancias de una clase anónima.

Pensando si podría deberse a que la clase local es estática, lo eliminé y no importó.

En mi caso, estaba haciendo algo 1000, elijo 3 veces, que es 499.500. La versión con la clase local (independientemente de la estática o no) tomó 26 segundos y la versión con la clase anónima funcionalmente idéntica tomó 2 minutos y 20 segundos.

En cuanto al rendimiento, debes considerar si una clase interna debería crearse o no.

Un ejemplo de mala práctica es algo así como:

 public List someMethod() { return new ArrayList() {{ add("Item one"); add("Item two"); }}; } 

Si bien esta conveniencia sintáctica se ve inteligente a primera vista, esto (a menudo inadvertido) crea una clase interna anónima cuyo objeto guarda una referencia a la instancia externa. Como este objeto también se da al exterior como valor de resultado de someMethod, no puede estar seguro de lo que hace la persona que llama con esta lista. Si coloca la instancia ArrayList resultante en alguna variable estática, ¡su Objeto actual también se mantendrá para siempre!

Especular sobre el rendimiento del código es una excelente manera de perder tu tiempo. Nada se compara con comparar realmente el código. Si le preocupa el rendimiento, mida el código . Si sospecha que su código no es óptimo, perfile el código para averiguar dónde se gasta el tiempo, luego intente mejorar esas partes. En este momento, puede ser apropiado estudiar realmente el código de bytes para ver si eso puede darle una pista sobre qué implementación es más eficiente.

Cuando haya hecho eso, vuelva a medir el código para asegurarse de no empeorar las cosas, por ejemplo, haciendo el código más feo y más difícil de mantener.