variable error cannot java list

error - ¿Por qué list.size()> 0 es más lento que list.isEmpty() en Java?



javac error cannot find symbol (9)

.size () tiene que mirar la lista completa, mientras que .isEmpty () puede detenerse en la primera.

Obviamente, depende de la implementación, pero como se ha dicho antes, si no necesita saber el tamaño real, ¿por qué molestarse en contar todos los elementos?

¿Por qué list.size()>0 más lento que list.isEmpty() en Java? En otras palabras, ¿ isEmpty() qué es preferible isEmpty() en lugar de size()>0 ?

Cuando veo la implementación en ArrayList , parece que la velocidad debería ser la misma:

ArrayList.size ()

/** * Returns the number of elements in this list. * * @return the number of elements in this list */ public int size() { return size; }

ArrayList.isEmpty ()

/** * Returns <tt>true</tt> if this list contains no elements. * * @return <tt>true</tt> if this list contains no elements */ public boolean isEmpty() { return size == 0; }

Si solo escribimos un programa simple para que los dos métodos tomen el tiempo, ese size() caso size() tomará más isEmpty() en todos los casos, ¿por qué esto es así?

Aquí está mi código de prueba;

import java.util.List; import java.util.Vector; public class Main { public static void main(String[] args) { List l=new Vector(); int i=0; for(i=0;i<10000;i++){ l.add(new Integer(i).toString()); } System.out.println(i); Long sTime=System.nanoTime(); l.size(); Long eTime=System.nanoTime(); l.isEmpty(); Long eeTime=System.nanoTime(); System.out.println(eTime-sTime); System.out.println(eeTime-eTime); } }

Aquí eTime-sTime>eeTime-eTime en todos los casos. ¿Por qué?


Contar elementos en una lista enlazada puede ser muy lento.


Dadas esas dos implementaciones, la velocidad debería ser la misma, eso es cierto.

Pero esas no son, de lejos, las únicas implementaciones posibles para estos métodos. Una lista enlazada primitiva (una que no almacena el tamaño por separado), por ejemplo, podría responder a isEmpty() mucho más rápido que una llamada de size() .

Más importante aún: isEmpty() describe su intento exactamente, mientras que size()==0 es innecesariamente complejo (no muy complejo, por supuesto, pero se debe evitar cualquier complejidad innecesaria).


De acuerdo con PMD (analizador de código fuente Java basado en un conjunto de reglas estático) se prefiere IsEmpty (). Puedes encontrar el conjunto de reglas PMD aquí. Busque la regla "UseCollectionIsEmpty".

http://pmd.sourceforge.net/rules/design.html

Según mi opinión, también ayuda a mantener el código fuente completo en lugar de la mitad de la gente que usa isEmpty () y el resto usa size () == 0.


En general, es imposible decir cuál es más rápido, ya que depende de la implementación de la List de interfaces que esté utilizando.

Supongamos que estamos hablando de ArrayList . Busque el código fuente de ArrayList , puede encontrarlo en el archivo src.zip en su directorio de instalación de JDK. El código fuente de los métodos es isEmpty y el size ve de la siguiente manera (Sun JDK 1.6 actualización 16 para Windows):

public boolean isEmpty() { return size == 0; } public int size() { return size; }

Puede ver fácilmente que ambas expresiones isEmpty() y size() == 0 se reducen exactamente a las mismas declaraciones, por lo que una no es más rápida que la otra.

Si está interesado en cómo funciona para otras implementaciones de la List de interfaces, busque el código fuente y descúbralo.



Para ArrayList s, sí, tienes razón en que las operaciones toman (aproximadamente) el mismo tiempo.

Por ejemplo, para otras implementaciones de listas - listas vinculadas ingenuas *, contar el tamaño puede llevar mucho tiempo, mientras que en realidad solo importa si es mayor que cero.

Entonces, si usted sabe absolutamente que la lista es una implementación de ArrayList y nunca cambiará, entonces realmente no importa; pero:

  1. Esta es una mala práctica de programación de todos modos para atarte a una implementación específica.
  2. Si las cosas cambian unos años después de la reestructuración de código, las pruebas mostrarán que "funciona" pero que las cosas se ejecutan con menos eficiencia que antes
  3. Incluso en el mejor de los casos, size() == 0 aún no es más rápido que isEmpty() , por lo que no hay ninguna razón convincente para usar el primero.
  4. isEmpty es una definición más clara de qué es lo que realmente te importa y lo que estás probando, por lo que hace que tu código sea un poco más fácil de entender.

(Además, revisaría el uso de NULL en el título de la pregunta; la pregunta en sí misma y estas operaciones no tienen nada que ver con si las referencias de los objetos son nulas).

* Originalmente escribí LinkedList aquí, haciendo referencia implícitamente a java.util.LinkedList, aunque esa implementación en particular almacena su longitud explícitamente, haciendo que el tamaño () sea una operación O (1) aquí. Una operación de lista enlazada más ingenua podría no hacer esto, y en el sentido más general no hay garantía de eficiencia en las implementaciones de List.


Su código de prueba es defectuoso.

Simplemente invierta el orden, es decir, llame a isEmpty first y size> 0 second y obtendrá el resultado opuesto . Esto se debe a la carga de clases, almacenamiento en caché, etc.


Tu dijiste:

Aquí eTime-sTime>eeTime-eTime en todos los casos ¿Por qué?

En primer lugar, es probable que sea debido a su código de prueba. No puede probar la velocidad de llamar a l.size () y l.isEmpty () al mismo tiempo, ya que ambos consultan el mismo valor. Lo más probable es que la llamada a l.size () haya cargado el tamaño de su lista en su caché de CPU y la llamada a l.isEmpty () es mucho más rápida como resultado.

Puede intentar llamar a l.size () un par de millones de veces y l.isEmpty () un par de millones de veces en dos programas separados, pero en teoría el compilador podría optimizar todas esas llamadas ya que en realidad no está haciendo nada con Los resultados.

En cualquier caso, la diferencia de rendimiento entre los dos será despreciable, especialmente una vez que haga la comparación que debe hacer para ver si la lista está vacía ( l.size() == 0 ). Lo más probable es que el código generado se vea casi completamente similar. Como han señalado otros carteles, en este caso desea optimizar la legibilidad, no la velocidad.

Edición: lo he probado yo mismo. Es casi un lanzamiento. size() y isEmpty() utilizados en Vector dieron resultados diferentes en carreras largas, ni vencieron al otro de forma consistente. Cuando se ejecuta en un ArrayList size() parecía más rápido, pero no mucho. Lo más probable es que esto se deba al hecho de que el acceso a Vector está sincronizado, por lo que lo que realmente se ve cuando se intenta comparar el acceso a estos métodos es la sobrecarga de sincronización, que puede ser muy delicada.

Lo que hay que quitar aquí es que cuando intentas optimizar una llamada de método con una diferencia de nanosegundos en el tiempo de ejecución, entonces lo estás haciendo mal . En primer lugar, obtenga lo básico correctamente, como usar Long s donde debería usar long .