Estaba leyendo el ArrayListcódigo fuente de Java y noté algunas comparaciones en sentencias if.
En Java 7, el método grow(int)usa
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
En Java 6, growno existía. Sin ensureCapacity(int)embargo, el método utiliza
if (newCapacity < minCapacity)
newCapacity = minCapacity;
¿Cuál fue la razón detrás del cambio? ¿Fue un problema de rendimiento o simplemente un estilo?
Me imagino que comparar con cero es más rápido, pero realizar una resta completa solo para verificar si es negativo me parece un poco exagerado. También en términos de bytecode, esto implicaría dos instrucciones ( ISUBy IF_ICMPGE) en lugar de una ( IFGE).
java
if-statement
arraylist
dejvuth
fuente
fuente

if (newCapacity - minCapacity < 0)mejor queif (newCapacity < minCapacity)en términos de prevención de desbordamiento?Respuestas:
a < bya - b < 0puede significar dos cosas diferentes. Considere el siguiente código:Cuando se ejecuta, esto solo se imprimirá
a - b < 0. Lo que sucede es quea < bes claramente falso, pero sea - bdesborda y se vuelve-1negativo.Ahora, dicho esto, considere que la matriz tiene una longitud muy cercana
Integer.MAX_VALUE. El código enArrayListva así:oldCapacityestá realmente cerca deInteger.MAX_VALUElonewCapacityque (que esoldCapacity + 0.5 * oldCapacity) podría desbordarse y volverseInteger.MIN_VALUE(es decir, negativo). Luego, restando losminCapacitysubflujos nuevamente en un número positivo.Esta verificación asegura que
ifno se ejecute. Si el código se escribiera comoif (newCapacity < minCapacity), seríatrueen este caso (ya quenewCapacityes negativo), por lo quenewCapacityse vería obligado a hacerlominCapacityindependientemente deoldCapacity.Este caso de desbordamiento es manejado por el siguiente if. Cuando se
newCapacityha desbordado, esto serátrue:MAX_ARRAY_SIZEse define comoInteger.MAX_VALUE - 8yInteger.MIN_VALUE - (Integer.MAX_VALUE - 8) > 0estrue. PornewCapacitylo tanto, se maneja correctamente: elhugeCapacitymétodo devuelveMAX_ARRAY_SIZEoInteger.MAX_VALUE.NB: esto es lo que dice el
// overflow-conscious codecomentario en este método.fuente
a - by verificando si el bit superior es a1. ¿Cómo manejan el desbordamiento?Encontré esta explicación :
En Java 6, si usa la API como:
Y los
newCountdesbordamientos (esto se vuelve negativo),if (minCapacity > oldCapacity)devolverán falso y puede suponer erróneamente queArrayListse incrementó enlen.fuente
ensureCapacity; siminCapacityes negativo, nunca se llega a ese punto, se ignora tan silenciosamente como la complicada implementación pretende evitar. Entonces, "no podemos hacer esto" para la compatibilidad de API pública es un argumento extraño como ya lo hicieron. Las únicas personas que llaman confiando en este comportamiento son las internas.minCapacityes muy negativo (es decir, como resultado delintdesbordamiento al agregar el tamaño actual de ArrayList a la cantidad de elementos que desea agregar),minCapacity - elementData.lengthpara desbordarse nuevamente y volverse positivo. Así lo entiendo.if (minCapacity > minExpand), lo cual no entiendo.addAllmétodos son el único caso en el que es relevante ya que la suma del tamaño actual y el número de elementos nuevos pueden desbordarse. Sin embargo, estas son llamadas internas y el argumento "no podemos cambiarlo porqueensureCapacityes una API pública" es un argumento extraño cuando, de hecho,ensureCapacityignora los valores negativos. La API de Java 8 no cambió ese comportamiento, todo lo que hace es ignorar las capacidades por debajo de la capacidad predeterminada cuandoArrayListestá en su estado inicial (es decir, inicializado con capacidad predeterminada y aún vacío).newcount = count + lenes correcto cuando se trata del uso interno, sin embargo, no se aplica alpublicmétodoensureCapacity()...Mirando el código:
Si
oldCapacityes bastante grande, se desbordará ynewCapacityserá un número negativo. Una comparación comonewCapacity < oldCapacityse evaluará incorrectamentetrueyArrayListno crecerá.En cambio, el código tal como está escrito (
newCapacity - minCapacity < 0devuelve falso) permitirá que el valor negativo denewCapacityse evalúe más en la siguiente línea, lo que resulta en recalcularnewCapacityinvocandohugeCapacity(newCapacity = hugeCapacity(minCapacity);) para permitirArrayListque crezcaMAX_ARRAY_SIZE.Esto es lo que el
// overflow-conscious codecomentario intenta comunicar, aunque de manera bastante oblicua.Por lo tanto, en resumen, la nueva comparación protege contra la asignación de un valor
ArrayListmayor que el predefinido, alMAX_ARRAY_SIZEtiempo que le permite crecer hasta ese límite si es necesario.fuente
Las dos formas se comportan exactamente igual a menos que la expresión se
a - bdesborde, en cuyo caso son opuestas. Siaes un gran negativo, ybes un gran positivo, entonces(a < b)es claramente cierto, peroa - bse desbordará para volverse positivo, por lo que(a - b < 0)es falso.Si está familiarizado con el código de ensamblaje x86, considere que
(a < b)lo implementa ajge, que se ramifica alrededor del cuerpo de la instrucción if cuando SF = OF. Por otro lado,(a - b < 0)actuará como ajns, que se ramifica cuando SF = 0. Por lo tanto, estos se comportan de manera diferente precisamente cuando OF = 1.fuente