1. Explicación
Con respecto al método transversal de mapas en Java, muchos artículos recomiendan el uso de EntrySet, que se considera mucho más eficiente que KeySet. La razón es: el método EntrySet obtiene el conjunto de todas las claves y valores a la vez; mientras que keySet obtiene solo el conjunto de claves. Para cada clave, el valor debe buscarse en el Mapa una vez más, reduciendo así el valor. eficiencia general. ¿Cuál es entonces la situación real?
Para comprender la brecha real en el rendimiento transversal, incluidas las diferencias en diferentes escenarios, como atravesar clave + valor, atravesar clave, atravesar valor, etc., intenté realizar algunas pruebas comparativas.
2. Pruebas comparativas
Al principio, solo se realizó una prueba simple, pero los resultados mostraron que el rendimiento de keySet era mejor, lo que me desconcertó. ¿No dicen todos que EntrySet es obviamente mejor que KeySet? Para realizar una mayor verificación, se utilizaron diferentes datos de prueba para pruebas comparativas más detalladas.
2.1 Datos de prueba
2.1.1 Datos de prueba de HashMap
HashMap-1, el tamaño es 1 millón, la clave y el valor son String, el valor de la clave es 1, 2, 3...1000000:
Copie el código de código de la siguiente manera:
Mapa<Cadena, Cadena> mapa = nuevo HashMap<Cadena, Cadena>();
Clave de cadena, valor;
para (i = 1; i <= número; i++) {
clave = "" + yo;
valor = "valor";
map.put(clave, valor);
}
HashMap-2, el tamaño es 1 millón, la clave y el valor son String, el valor de la clave es 50, 100, 150, 200,..., 50000000:
Copie el código de código de la siguiente manera:
Mapa<Cadena, Cadena> mapa = nuevo HashMap<Cadena, Cadena>();
Clave de cadena, valor;
para (i = 1; i <= número; i++) {
clave = "" + (i * 50);
valor = "valor";
map.put(clave, valor);
}
2.1.2 Datos de prueba de TreeMap
TreeMap-1, el tamaño es 1 millón, la clave y el valor son String, el valor de la clave es 1, 2, 3...1000000:
Copie el código de código de la siguiente manera:
Mapa<Cadena, Cadena> mapa = nuevo TreeMap<Cadena, Cadena>();
Clave de cadena, valor;
para (i = 1; i <= número; i++) {
clave = "" + yo;
valor = "valor";
map.put(clave, valor);
}
TreeMap-2, el tamaño es 1 millón, la clave y el valor son String, los valores clave son 50, 100, 150, 200,..., 50000000, más discretos:
Copie el código de código de la siguiente manera:
Mapa<Cadena, Cadena> mapa = nuevo TreeMap<Cadena, Cadena>();
Clave de cadena, valor;
para (i = 1; i <= número; i++) {
clave = "" + (i * 50);
valor = "valor";
map.put(clave, valor);
}
2.2 Escenario de prueba
Utilice varios métodos de escritura de keySet, EntrySet y Values para probar tres escenarios: atravesar clave + valor, atravesar clave y atravesar valor.
2.2.1 Clave transversal + valor
keySet atraviesa clave + valor (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Cadena> iter = map.keySet().iterator();
mientras (iter.hasNext()) {
clave = iter.siguiente();
valor = mapa.get(clave);
}
keySet atraviesa clave + valor (método de escritura 2):
Copie el código de código de la siguiente manera:
para (clave de cadena: map.keySet()) {
valor = mapa.get(clave);
}
EntrySet atraviesa clave + valor (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Entrada<Cadena, Cadena>> iter = map.entrySet().iterator();
Entrada<Cadena, Cadena> entrada;
mientras (iter.hasNext()) {
entrada = iter.siguiente();
clave = entrada.getKey();
valor = entrada.getValue();
}
EntrySet atraviesa clave + valor (método de escritura 2):
Copie el código de código de la siguiente manera:
para (Entrada<Cadena, Cadena> entrada: map.entrySet()) {
clave = entrada.getKey();
valor = entrada.getValue();
}
2.2.2 Tecla de recorrido
keySet atraviesa la clave (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Cadena> iter = map.keySet().iterator();
mientras (iter.hasNext()) {
clave = iter.siguiente();
}
keySet atraviesa la clave (método de escritura 2):
Copie el código de código de la siguiente manera:
para (clave de cadena: map.keySet()) {
}
EntrySet atraviesa la clave (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Entrada<Cadena, Cadena>> iter = map.entrySet().iterator();
mientras (iter.hasNext()) {
clave = iter.next().getKey();
}
EntrySet atraviesa la clave (método de escritura 2):
Copie el código de código de la siguiente manera:
para (Entrada<Cadena, Cadena> entrada: map.entrySet()) {
clave = entrada.getKey();
}
2.2.3 Valor transversal
keySet atraviesa el valor (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Cadena> iter = map.keySet().iterator();
mientras (iter.hasNext()) {
valor = mapa.get(iter.next());
}
keySet atraviesa el valor (método de escritura 2):
Copie el código de código de la siguiente manera:
para (clave de cadena: map.keySet()) {
valor = mapa.get(clave);
}
EntrySet atraviesa el valor (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Entrada<Cadena, Cadena>> iter = map.entrySet().iterator();
mientras (iter.hasNext()) {
valor = iter.next().getValue();
}
EntrySet atraviesa el valor (método de escritura 2):
Copie el código de código de la siguiente manera:
para (Entrada<Cadena, Cadena> entrada: map.entrySet()) {
valor = entrada.getValue();
}
los valores atraviesan el valor (método de escritura 1):
Copie el código de código de la siguiente manera:
Iterador<Cadena> iter = map.values().iterator();
mientras (iter.hasNext()) {
valor = iter.siguiente();
}
los valores atraviesan el valor (método de escritura 2):
Copie el código de código de la siguiente manera:
para (valor de cadena: map.values()) {
}
2.3 Resultados de la prueba
2.3.1 Resultados de la prueba HashMap
Unidad: milisegundo | HashMap-1 | HashMap-2 |
| keySet atraviesa clave + valor (método de escritura 1) | 39 | 93 |
| keySet atraviesa clave + valor (método de escritura 2) | 38 | 87 |
| EntrySet atraviesa clave + valor (método de escritura 1) | 43 | 86 |
| EntrySet atraviesa clave + valor (método de escritura 2) | 43 | 85 |
Unidad: milisegundo | HashMap-1 | HashMap-2 |
| keySet atraviesa la clave (método de escritura 1) | 27 | 65 |
| keySet atraviesa la clave (método de escritura 2) | 26 | 64 |
| EntrySet atraviesa la clave (método de escritura 1) | 35 | 75 |
| EntrySet atraviesa la clave (método de escritura 2) | 34 | 74 |
Unidad: milisegundo | HashMap-1 | HashMap-2 |
| keySet atraviesa el valor (método de escritura 1) | 38 | 87 |
| keySet atraviesa el valor (método de escritura 2) | 37 | 87 |
| EntrySet atraviesa el valor (método de escritura 1) | 34 | 61 |
| EntrySet atraviesa el valor (método de escritura 2) | 32 | 62 |
| valores valor transversal (método de escritura 1) | 26 | 48 |
| valores valor transversal (método de escritura 2) | 26 | 48 |
2.3.2 Resultados de la prueba TreeMap
Unidad: milisegundo | Mapa de árbol-1 | Mapa de árbol-2 |
| keySet atraviesa clave + valor (método de escritura 1) | 430 | 451 |
| keySet atraviesa clave + valor (método de escritura 2) | 429 | 450 |
| EntrySet atraviesa clave + valor (método de escritura 1) | 77 | 84 |
| EntrySet atraviesa clave + valor (método de escritura 2) | 70 | 68 |
Unidad: milisegundo | Mapa de árbol-1 | Mapa de árbol-2 |
| keySet atraviesa la clave (método de escritura 1) | 50 | 49 |
| keySet atraviesa la clave (método de escritura 2) | 49 | 48 |
| EntrySet atraviesa la clave (método de escritura 1) | 66 | 64 |
| EntrySet atraviesa la clave (método de escritura 2) | 65 | 63 |
Unidad: milisegundo | Mapa de árbol-1 | Mapa de árbol-2 |
| keySet atraviesa el valor (método de escritura 1) | 432 | 448 |
| keySet atraviesa el valor (método de escritura 2) | 430 | 448 |
| EntrySet atraviesa el valor (método de escritura 1) | 62 | 61 |
| EntrySet atraviesa el valor (método de escritura 2) | 62 | 61 |
| valores valor transversal (método de escritura 1) | 46 | 46 |
| valores valor transversal (método de escritura 2) | 45 | 46 |
3. Conclusión
3.1 Si usas HashMap
1. Al atravesar la clave y el valor al mismo tiempo, la diferencia de rendimiento entre los métodos keySet y EntrySet depende de las condiciones específicas de la clave, como la complejidad (objetos complejos), la discreción, la tasa de conflicto, etc. En otras palabras, depende del costo de buscar valor en HashMap. La operación de EntrySet para recuperar todas las claves y valores a la vez tiene una sobrecarga de rendimiento. Cuando esta pérdida es menor que la sobrecarga de HashMap para buscar valor, se reflejará la ventaja de rendimiento de EntrySet. Por ejemplo, en la prueba de comparación anterior, cuando la clave es la cadena numérica más simple, keySet puede ser más eficiente y requiere un 10 % menos de tiempo que EntrySet. En términos generales, se recomienda utilizar EntrySet. Porque cuando la clave es muy simple, su rendimiento puede ser ligeramente menor que el de keySet, pero es controlable a medida que la clave se vuelve más complicada, las ventajas de EntrySet se reflejarán claramente; Por supuesto, podemos elegir según la situación real.
2. Cuando solo se atraviesan claves, el método keySet es más apropiado, porque EntrySet también elimina valores inútiles, lo que desperdicia rendimiento y espacio. En los resultados de las pruebas anteriores, keySet tarda un 23% menos que el método EntrySet.
3. Cuando solo se recorre el valor, usar el método vlaues es la mejor opción, EntrySet es ligeramente mejor que el método KeySet.
4. Entre los diferentes métodos de escritura transversal, se recomienda utilizar el siguiente método de escritura, que es un poco más eficiente:
Copie el código de código de la siguiente manera:
para (clave de cadena: map.keySet()) {
valor = mapa.get(clave);
}
para (Entrada<Cadena, Cadena> entrada: map.entrySet()) {
clave = entrada.getKey();
valor = entrada.getValue();
}
para (valor de cadena: map.values()) {
}
3.2 Si usas TreeMap
1. Al atravesar la clave y el valor al mismo tiempo, a diferencia de HashMap, el rendimiento de EntrySet es mucho mayor que el de KeySet. Esto está determinado por la eficiencia de la consulta de TreeMap. En otras palabras, el costo de buscar valor en TreeMap es relativamente alto, que es significativamente mayor que el costo de recuperar todas las claves y valores a la vez desde EntrySet. Por lo tanto, se recomienda encarecidamente utilizar el método EntrySet al atravesar un TreeMap.
2. Cuando solo se atraviesan claves, el método keySet es más apropiado, porque EntrySet también elimina valores inútiles, lo que desperdicia rendimiento y espacio. En los resultados de las pruebas anteriores, keySet tarda un 24% menos que el método EntrySet.
3. Cuando solo se recorre el valor, usar el método vlaues es la mejor opción, y EntrySet también es obviamente mejor que el método keySet.
4. Entre los diferentes métodos de escritura transversal, se recomienda utilizar el siguiente método de escritura, que es un poco más eficiente:
Copie el código de código de la siguiente manera:
para (clave de cadena: map.keySet()) {
valor = mapa.get(clave);
}
para (Entrada<Cadena, Cadena> entrada: map.entrySet()) {
clave = entrada.getKey();
valor = entrada.getValue();
}
para (valor de cadena: map.values()) {
}