Haga un buen uso de esta biblioteca de herramientas Java, y la cantidad de código se puede reducir directamente en un 50%

¡Haga un buen uso de esta biblioteca de herramientas Java y la cantidad de código se reducirá directamente en un 50%!

Guava es un kit de herramientas de extensión de la biblioteca de clases de Java desarrollado por Google, que contiene una gran cantidad de API, que cubre colecciones, almacenamiento en caché, concurrencia, E/S y muchos otros aspectos. Por un lado, el uso de estas API puede simplificar nuestro código y hacerlo más elegante, por otro lado, complementa muchas funciones que no están en jdk, lo que puede hacer que nuestro desarrollo sea más eficiente.

Lo que les compartiré hoy son algunas de Maplas operaciones coquetas encapsuladas en Guava, después de usar estas funciones, tengo que decir algo muy dulce. Primero introduzca las coordenadas dependientes y luego comience nuestra experiencia formal~

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1.1-jre</version>
</dependency>

Tabla - Mapa de doble llave

Solo uno y uno están Mappermitidos en java , pero uno puede existir en guayaba . Los dos en se denominan y , es decir, fila y columna, respectivamente. (Pero personalmente siento que no es muy exacto entenderlos como filas y columnas. Puede ser más apropiado considerarlos como dos columnas)keyvalueTablevaluekeyTablekeyrowKeycolumnKey

Para dar un ejemplo simple, si desea registrar la cantidad de días que trabaja un empleado cada mes. Si usa la Mapimplementación ordinaria en Java, necesita dos niveles de anidamiento:

Map<String,Map<String,Integer>> map=new HashMap<>();
//存放元素
Map<String,Integer> workMap=new HashMap<>();
workMap.put("Jan",20);
workMap.put("Feb",28);
map.put("Hydra",workMap);

//Recuperar elementos
Integer dayCount = map.get("Hydra").get("Jan");

Es muy sencillo si lo usas Table, échale un vistazo al código simplificado:

Table<String,String,Integer> table= HashBasedTable.create();
//存放元素
table.put("Hydra", "Jan", 20);
table.put("Hydra", "Feb", 28);

table.put("Troncos", "Ene", 28);
table.put("Troncos", "Feb", 16);

//Recuperar elementos
Integer dayCount = table.get("Hydra", "Feb");

Ya no necesitamos construir dos capas complicadas Map, podemos hacerlo directamente en una capa. Además del acceso a los elementos, veamos otras operaciones prácticas.

1. Obtener el conjunto de clave o valor

//rowKey或columnKey的集合
Set<String> rowKeys = table.rowKeySet();
Set<String> columnKeys = table.columnKeySet();

//valor集合
Colección<Integer> valores = table.values();

Imprima sus resultados por separado, keyla colección no contiene elementos duplicados y valuela colección contiene todos los elementos sin deduplicación:

[Hydra, Trunks]
[Jan, Feb]
[20, 28, 28, 16]

2. Calcular la suma de todos los valores correspondientes a la clave

Tome la suma de todas las estadísticas rowKeycorrespondientes valuecomo ejemplo:

for (String key : table.rowKeySet()) {
    Set<Map.Entry<String, Integer>> rows = table.row(key).entrySet();
    int total = 0;
    for (Map.Entry<String, Integer> row : rows) {
        total += row.getValue();
    }
    System.out.println(key + ": " + total);
}

Imprimir resultado:

Hydra: 48
Trunks: 44

3. Convertir clave de fila y clave de columna

Esta operación también puede entenderse como la transposición de filas y columnas, Tablesun método estático llamado directamente transpose:

Table<String, String, Integer> table2 = Tables.transpose(table);
Set<Table.Cell<String, String, Integer>> cells = table2.cellSet();
cells.forEach(cell->
    System.out.println(cell.getRowKey()+","+cell.getColumnKey()+":"+cell.getValue())
);

Use cellSetel método para obtener todas las filas de datos, imprima los resultados y podrá ver rowque columnse ha producido el intercambio:

Jan,Hydra:20
Feb,Hydra:28
Jan,Trunks:28
Feb,Trunks:16

4. Convertir a un mapa anidado

¿Aún recuerda el formato en el que almacenamos Tablelos datos antes de usarlos? Si desea restaurar los datos a la Mapforma anidada, puede usar el método o para Tablelograrlo rowMap:columnMap

Map<String, Map<String, Integer>> rowMap = table.rowMap();
Map<String, Map<String, Integer>> columnMap = table.columnMap();

Vea el contenido en el formato convertido Map, que se resume por fila y columna:

{Hydra={Jan=20, Feb=28}, Trunks={Jan=28, Feb=16}}
{Jan={Hydra=20, Trunks=28}, Feb={Hydra=28, Trunks=16}}

BiMap - Mapa bidireccional

En general Map, si desea buscar valueel objeto correspondiente key, no hay una manera fácil. Ya sea que use forun bucle o un iterador, debe recorrer todo el objeto Map. Por ejemplo, en un bucle keySet:

public List<String> findKey(Map<String, String> map, String val){
    List<String> keys=new ArrayList<>();
    for (String key : map.keySet()) {
        if (map.get(key).equals(val))
            keys.add(key);
    }
    return keys;
}

Sin embargo, Guava BiMapproporciona una estructura de datos asociada keycon valuedos direcciones. Veamos un ejemplo simple:

HashBiMap<String, String> biMap = HashBiMap.create();
biMap.put("Hydra","Programmer");
biMap.put("Tony","IronMan");
biMap.put("Thanos","Titan");
//使用key获取value
System.out.println(biMap.get("Tony"));

BiMap<String, String> inverse = biMap.inverse();
//使用value获取key
System.out.println(inverse.get("Titan"));

Resultados de la,:

IronMan
Thanos

Parece muy útil, ¿no? Sin embargo, todavía hay algunos escollos que evitar en el uso, que se resolverán uno por uno a continuación.

1. El impacto de la operación tras la reversión

Arriba usamos inverseel método para revertir el BiMapmapeo original de clave-valor, pero este objeto invertido BiMapno es un objeto nuevo, implementa una asociación de vista, por lo que BiMaptodas las operaciones realizadas en el invertido actuarán sobre el original BiMapsuperior.

HashBiMap<String, String> biMap = HashBiMap.create();
biMap.put("Hydra","Programmer");
biMap.put("Tony","IronMan");
biMap.put("Thanos","Titan");
BiMap<String, String> inverse = biMap.inverse();

inversa.put("IronMan","Stark");
Sistema.salida.println(biMap);

BiMapDespués de modificar el contenido en el invertido , mira BiMapde nuevo el contenido original:

{Hydra=Programmer, Thanos=Titan, Stark=IronMan}

IronManSe puede ver que la clave correspondiente al valor original es Tony, aunque no se ha modificado directamente, pero ahora la clave ha cambiado Stark.

2. El valor no se puede repetir

BiMapLa herencia subyacente de Map, sabemos que la duplicación no está permitida Mapen , y se puede considerar que la neutralización bidireccional está en una posición equivalente, por lo que se agregan restricciones sobre esta base y no se permite la duplicación. Echa un vistazo al código a continuación:keyBiMapkeyvaluevalue

HashBiMap<String, String> biMap = HashBiMap.create();
biMap.put("Tony","IronMan");
biMap.put("Stark","IronMan");

De esta forma, el código no puede terminar normalmente y IllegalArgumentExceptionse lanzará una excepción:

Si realmente desea asignar el nuevo keyal existente value, también puede usar forcePutel método para forzar el reemplazo del original key:

HashBiMap<String, String> biMap = HashBiMap.create();
biMap.put("Tony","IronMan");
biMap.forcePut("Stark","IronMan");

Imprime el reemplazado BiMap:

{Stark=IronMan}

Por cierto, dado que BiMapno valuepermite la repetición, su valuesmétodo no devuelve repetición Set, no ordinario Collection:

Set<String> values = biMap.values();

Multimap - Mapa multivalor

Java Mapmantiene una relación clave-valor de uno a uno. Si desea asignar una clave a varios valores, solo puede establecer el contenido del valor como una colección. La implementación simple es la siguiente:

Map<String, List<Integer>> map=new HashMap<>();
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
map.put("day",list);

Guava Multimapproporciona una forma de asignar una clave a múltiples valores. No necesita definir colecciones internas complejas. Puede usarlo como uno normal. MapDefina y coloque los datos de la siguiente manera:

Multimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.put("day",1);
multimap.put("day",2);
multimap.put("day",8);
multimap.put("month",3);

Imprime Multimapel contenido de esto, y podrás ver intuitivamente que cada keycorrespondiente es una colección:

{month=[3], day=[1, 2, 8]}

1. Obtenga una colección de valores

En la operación anterior, el método normal creado Multimapdevolverá get(key)una Collectioncolección de tipo:

Collection<Integer> day = multimap.get("day");

Si se especifica como ArrayListMultimapun tipo en el momento de la creación, getel método devolverá un List:

ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
List<Integer> day = multimap.get("day");

De la misma manera, también puede crear tipos HashMultimap, etc.TreeMultimapMultimap

MultimapEl getmétodo devolverá una no nullcolección, pero el contenido de esta colección puede estar vacío, observe el siguiente ejemplo:

List<Integer> day = multimap.get("day");
List<Integer> year = multimap.get("year");
System.out.println(day);
System.out.println(year);

Imprimir resultado:

[1, 2, 8]
[]

2. La colección después de la operación get

Similar al BiMapuso de , getla colección devuelta por el método no es un objeto independiente. Puede entenderse como la asociación de la vista de colección. La operación en esta nueva colección seguirá actuando en la original Multimap. Eche un vistazo a lo siguiente ejemplo:

ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.put("day",1);
multimap.put("day",2);
multimap.put("day",8);
multimap.put("month",3);

List<Integer> dia = multimap.get("dia");
List<Integer> mes = multimap.get("mes");

day.remove(0);//Este 0 es el subíndice
month.add(12);
System.out.println(multimap);

Mira los resultados modificados:

{month=[3, 12], day=[2, 8]}

3. Convertir a Mapa

Usando asMapel método, se puede Multimapconvertir al Map<K,Collection>formulario, y esto Maptambién se puede considerar como una vista asociada, y Mapla operación en esto actuará en el original Multimap.

Map<String, Collection<Integer>> map = multimap.asMap();
for (String key : map.keySet()) {
    System.out.println(key+" : "+map.get(key));
}
map.get("day").add(20);
System.out.println(multimap);

Resultados de la:

month : [3]
day : [1, 2, 8]
{month=[3], day=[1, 2, 8, 20]}

4. Problemas de cantidad

MultimapEl número en también es algo confuso en su uso, primero mire el siguiente ejemplo:

System.out.println(multimap.size());
System.out.println(multimap.entries().size());
for (Map.Entry<String, Integer> entry : multimap.entries()) {
    System.out.println(entry.getKey()+","+entry.getValue());
}

Imprimir resultado:

4
4
month,3
day,1
day,2
day,8

Esto se debe a que size()el método devuelve todas las asignaciones keya una sola value, por lo que el resultado es 4, entries()y el método es el mismo, devolviendo una colección de pares clave-valor keycon una sola . valuePero keySetalmacena un número diferente key, por ejemplo, el resultado impreso por la siguiente línea de código será 2.

System.out.println(multimap.keySet().size());

Luego mire convertirlo a Map, la cantidad cambia:

Set<Map.Entry<String, Collection<Integer>>> entries = multimap.asMap().entrySet();
System.out.println(entries.size());

El resultado de la ejecución del código es 2, porque obtuvo la relación de asignación keya Collection.

RangeMap - Mapa de rango

Primero veamos un ejemplo, suponiendo que queremos clasificar los puntajes de las pruebas en función de los puntajes, entonces habrá algo desagradable como esto en el código if-else:

public static String getRank(int score){
    if (0<=score && score<60)
        return "fail";
    else if (60<=score && score<=90)
        return "satisfactory";
    else if (90<score && score<=100)
        return "excellent";
    return null;
}

La descripción en guayaba RangeMapdescribe una relación de mapeo de un intervalo a un valor específico, lo que nos permite escribir código de una manera más elegante. Modifiquemos RangeMapel código anterior y probemos:

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closedOpen(0,60),"fail");
rangeMap.put(Range.closed(60,90),"satisfactory");
rangeMap.put(Range.openClosed(90,100),"excellent");

System.out.println(rangeMap.get(59));
System.out.println(rangeMap.get(60));
System.out.println(rangeMap.get(90));
System.out.println(rangeMap.get(91));

En el código anterior, [0,60)los intervalos cerrados a la izquierda y abiertos a la derecha, [60,90]los intervalos cerrados y (90,100]los intervalos abiertos a la izquierda y cerrados a la derecha se crean sucesivamente y se asignan a ciertos valores respectivamente. El resultado de la ejecución imprime:

fail
satisfactory
satisfactory
excellent

[70,80]Por supuesto, también podemos eliminar una sección de espacio.Después de que el siguiente código elimina este intervalo cerrado, getel resultado devuelto cuando se ejecuta de nuevo es null:

rangeMap.remove(Range.closed(70,80));
System.out.println(rangeMap.get(75));

ClassToInstanceMap - Mapa de instancias

ClassToInstanceMapes especial Map, su clave es Classy el valor es el Classobjeto de instancia correspondiente. Primero veamos un ejemplo simple del uso de putInstancemétodos para almacenar objetos:

ClassToInstanceMap<Object> instanceMap = MutableClassToInstanceMap.create();
User user=new User("Hydra",18);
Dept dept=new Dept("develop",200);

instanciaMap.putInstance(Usuario.clase,usuario);
instanceMap.putInstance(Depto.clase,depto);

Utilice getInstanceel método para recuperar el objeto:

User user1 = instanceMap.getInstance(User.class);
System.out.println(user==user1);

Se imprime el resultado de la operación true, indicando que el objeto que se sacó es efectivamente el objeto que creamos y pusimos antes.

Quizás se pregunte, si solo guarda objetos, Map<Class,Object>también puede usar objetos ordinarios como este:

Map<Class,Object> map=new HashMap<>();
User user=new User("Hydra",18);
Dept dept=new Dept("develop",200);
map.put(User.class,user);
map.put(Dept.class,dept);

Entonces, ClassToInstanceMap¿cuáles son los beneficios de usar este enfoque?

En primer lugar, lo más obvio aquí es que se omite la compleja conversión de tipo obligatoria al sacar el objeto, y se evita el error de conversión de tipo manual. En segundo lugar, podemos ver ClassToInstanceMapla definición de la interfaz, que es genérica:

public interface ClassToInstanceMap<B> extends Map<Class<? extends B>, B>{...}

Este genérico también puede desempeñar un papel en la restricción del tipo. valuePara ajustarse al keytipo correspondiente, eche un vistazo al siguiente ejemplo:

ClassToInstanceMap<Map> instanceMap = MutableClassToInstanceMap.create();
HashMap<String, Object> hashMap = new HashMap<>();
TreeMap<String, Object> treeMap = new TreeMap<>();
ArrayList<Object> list = new ArrayList<>();

instanciaMap.putInstance(HashMap.class,hashMap);
instanciaMapa.putInstance(TreeMap.class,treeMap);

Esto se puede ejecutar normalmente, porque HashMapambos TreeMapintegran Mapla clase principal, pero si desea agregar otros tipos, compilará e informará un error.

Por lo tanto, si desea almacenar objetos en caché, pero no desea realizar una verificación de tipo compleja, puede usar lo que sea conveniente ClassToInstanceMap.

Resumir

Este artículo presenta 5 tipos Mapde estructuras de datos extendidas en guava, que brindan funciones muy prácticas y pueden simplificar enormemente nuestro código. Pero al mismo tiempo, hay muchas trampas que deben evitarse, como modificar la vista asociada que afectará los datos originales, etc. Debe ser más cauteloso en el uso específico.

Supongo que te gusta

Origin blog.csdn.net/dedede001/article/details/130681637
Recomendado
Clasificación