Guava: guarde código basura, escriba elegante y eficiente, y aumente la eficiencia N veces

Al mirar el código de un compañero de clase recientemente, descubrí que el código usa una gran parte del contenido de la biblioteca central de código abierto de Guava de Google, lo que hace que el código sea mucho más simple y claro, así que aprendí a compartir las funciones más útiles de Guava.

El proyecto Guava es la biblioteca principal de Java de código abierto de Google. Contiene principalmente algunas funciones de uso frecuente en el desarrollo de Java, como  verificación de datos  ,  colecciones inmutables  , recuento de colecciones, operaciones de mejora de colecciones, E / S, almacenamiento en caché, cadenas Operación, etc. Y Guava se  usa ampliamente en los proyectos internos de Java de Google, y también es ampliamente utilizado por otras empresas. Incluso  las excelentes bibliotecas de clases en Guava se introducen directamente en la nueva versión del JDK  , por lo que la calidad está fuera de toda duda.

El uso depende directamente de la introducción de mavan.

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.0-jre</version>
</dependency>

Validación de datos

La verificación de datos es muy simple de decir, uno es  un juicio no vacío  , el segundo es  el juicio de valor esperado  . Juicio no vacío Creo que todos los desarrolladores de Java están familiarizados con él y, a menudo, se ocuparon de NullPointException al principio. La forma en que lo manejamos es, naturalmente, un if (xx == null) que se puede resolver fácilmente. El juicio de valor esperado es similar, solo verifique si el valor de los datos es el resultado que desea.

Incluso con una operación tan simple, ¿a menudo cometemos errores? Además, el código escrito siempre se juzga línea por línea y es tan elegante sin importar cómo se mire. Afortunadamente, probemos Guayaba por primera vez.

Juicio no vacío

String param = "未读代码";
String name = Preconditions.checkNotNull(param);
System.out.println(name); // 未读代码
String param2 = null;
String name2 = Preconditions.checkNotNull(param2); // NullPointerException
System.out.println(name2);

Después de introducir Guava, puede usar Preconditions.checkNotNull directamente para un juicio no nulo. La ventaja es que hay dos, una es que la semántica es clara y el código es elegante; la otra es que puede personalizar el mensaje de error, por lo que si el parámetro está vacío, el mensaje de error es claro. Puede localizar parámetros específicos directamente.

String param2 = null;
String name2 = Preconditions.checkNotNull(param2,"param2 is null");
// java.lang.NullPointerException: param2 is null

Juicio de valor esperado

Al igual que en el juicio no vacío, puede comparar el valor actual y el valor esperado, y si no son iguales, puede personalizar el mensaje de error para lanzar.

String param = "www.wdbyte.com2";
String wdbyte = "www.wdbyte.com";
Preconditions.checkArgument(wdbyte.equals(param), "[%s] 404 NOT FOUND", param);
// java.lang.IllegalArgumentException: [www.wdbyte.com2] 404 NOT FOUND

¿Está fuera de límites?

La clase Preconditions también se puede utilizar para comprobar si los elementos de las matrices y las colecciones están fuera de los límites.

// Guava 中快速创建ArrayList
List<String> list = Lists.newArrayList("a", "b", "c", "d");
// 开始校验
int index = Preconditions.checkElementIndex(5, list.size());
// java.lang.IndexOutOfBoundsException: index (5) must be less than size (4)

La forma de crear rápidamente una Lista en el código también la proporciona Guava, y más adelante presentaremos en detalle las muchas poses creadas por la colección en Guava.

Colección inmutable

La creación de colecciones inmutables es una de mis razones favoritas para Guava, porque  es muy práctico crear una  colección que no se puede eliminar, modificar o agregar . No tienes que preocuparte por ningún problema con una colección de este tipo. En general, tiene las siguientes ventajas:

  1. Seguro para subprocesos, ya que no se puede modificar ningún elemento, se puede utilizar en varios subprocesos a voluntad y no hay problema de concurrencia.
  2. Se puede proporcionar a un tercero sin preocupaciones y no se puede modificar de todos modos.
  3. Reduzca la huella de memoria, ya que no se puede cambiar, la implementación interna puede ahorrar la huella de memoria en la mayor medida.
  4. Se puede utilizar como colección constante.

Método de creación

Habiendo dicho tanto, ¿cómo lo usas? Recoge rápidamente el código.

// 创建方式1:of
ImmutableSet<String> immutableSet = ImmutableSet.of("a", "b", "c");
immutableSet.forEach(System.out::println);
// a
// b
// c

// 创建方式2:builder
ImmutableSet<String> immutableSet2 = ImmutableSet.<String>builder()
    .add("hello")
    .add(new String("未读代码"))
    .build();
immutableSet2.forEach(System.out::println);
// hello
// 未读代码

// 创建方式3:从其他集合中拷贝创建
ArrayList<String> arrayList = new ArrayList();
arrayList.add("www.wdbyte.com");
arrayList.add("https");
ImmutableSet<String> immutableSet3 = ImmutableSet.copyOf(arrayList);
immutableSet3.forEach(System.out::println);
// www.wdbyte.com
// https

Los resultados del recorrido se pueden imprimir normalmente, pero si se realizan adiciones, eliminaciones y cambios, se informará directamente UnsupportedOperationException.

De hecho, también se proporciona una colección inmutable en el JDK, que se puede crear de la siguiente manera.

ArrayList<String> arrayList = new ArrayList();
arrayList.add("www.wdbyte.com");
arrayList.add("https");
// JDK Collections 创建不可变 List
List<String> list = Collections.unmodifiableList(arrayList);
list.forEach(System.out::println);// www.wdbyte.com https
list.add("未读代码"); // java.lang.UnsupportedOperationException

Precauciones

  1. Las colecciones inmutables creadas con Guava rechazan valores nulos, porque en la encuesta interna de Google no es necesario poner valores nulos en el 95% de los casos.
  2. Después de que la colección inmutable proporcionada por el JDK se haya creado con éxito, los elementos agregados de la colección original se reflejarán en la colección inmutable, y la colección inmutable de Guava no tendrá este problema.
   List<String> arrayList = new ArrayList<>();
   arrayList.add("a");
   arrayList.add("b");
   List<String> jdkList = Collections.unmodifiableList(arrayList);
   ImmutableList<String> immutableList = ImmutableList.copyOf(arrayList);
   arrayList.add("ccc");
   jdkList.forEach(System.out::println);// result: a b ccc
   System.out.println("-------");
   immutableList.forEach(System.out::println);// result: a b
  1. Si los elementos de la colección inmutable son objetos de referencia, los atributos de los objetos de referencia se pueden cambiar.

Otras colecciones inmutables

Colecciones inmutables Además del conjunto que se muestra arriba, hay muchas colecciones inmutables, a continuación se muestra la correspondencia entre colecciones inmutables y otras colecciones en Guayaba.

 

Fábrica de explotación colectiva

De hecho, aquí solo se presentará un método de creación, pero ¿por qué se presenta por separado? Si lo miras,  exclamarás que funciona  . Aunque JDK ha proporcionado una gran cantidad de métodos de operación relacionados con la colección, es muy conveniente de usar, pero Guava aún agrega algunos métodos muy útiles para asegurarse de que le encantará la última vez que lo use.

Crea una colección.

// 创建一个 ArrayList 集合
List<String> list1 = Lists.newArrayList();
// 创建一个 ArrayList 集合,同时塞入3个数据
List<String> list2 = Lists.newArrayList("a", "b", "c");
// 创建一个 ArrayList 集合,容量初始化为10
List<String> list3 = Lists.newArrayListWithCapacity(10);

LinkedList<String> linkedList1 = Lists.newLinkedList();
CopyOnWriteArrayList<String> cowArrayList = Lists.newCopyOnWriteArrayList();

HashMap<Object, Object> hashMap = Maps.newHashMap();
ConcurrentMap<Object, Object> concurrentMap = Maps.newConcurrentMap();
TreeMap<Comparable, Object> treeMap = Maps.newTreeMap();

HashSet<Object> hashSet = Sets.newHashSet();
HashSet<String> newHashSet = Sets.newHashSet("a", "a", "b", "c");

Guava agrega un método de creación de métodos de fábrica para cada colección. Los métodos de creación de métodos de fábrica de algunas colecciones se muestran arriba. ¿Es muy fácil de usar? Y puedes agregar algunos elementos directamente cuando lo creas. Esto es increíble, ya no necesitas agregar uno por uno.

Establecer intersección y diferencia de unión

Demasiado simple, solo mira el código y los resultados de salida.

Set<String> newHashSet1 = Sets.newHashSet("a", "a", "b", "c");
Set<String> newHashSet2 = Sets.newHashSet("b", "b", "c", "d");

// 交集
SetView<String> intersectionSet = Sets.intersection(newHashSet1, newHashSet2);
System.out.println(intersectionSet); // [b, c]

// 并集
SetView<String> unionSet = Sets.union(newHashSet1, newHashSet2);
System.out.println(unionSet); // [a, b, c, d]

// newHashSet1 中存在,newHashSet2 中不存在
SetView<String> setView = Sets.difference(newHashSet1, newHashSet2);
System.out.println(setView); // [a]

Numero de juegos

Esto es realmente útil, porque a menudo necesitamos diseñar una colección que se pueda contar, o una colección de mapas donde el valor es una Lista. Si no lo entiende, mire el siguiente código, ya sea que lo haya escrito así un día o una noche.

  1. Cuente el número de apariciones del mismo elemento (he escrito lo más breve posible en el código a continuación). Escritura nativa de JDK:
   // Java 统计相同元素出现的次数。
   List<String> words = Lists.newArrayList("a", "b", "c", "d", "a", "c");
   Map<String, Integer> countMap = new HashMap<String, Integer>();
   for (String word : words) {
       Integer count = countMap.get(word);
       count = (count == null) ? 1 : ++count;
       countMap.put(word, count);
   }
   countMap.forEach((k, v) -> System.out.println(k + ":" + v));
   /**
    * result:
    * a:2
    * b:1
    * c:2
    * d:1
    */

Aunque el código se ha optimizado tanto como sea posible, la cantidad de código sigue siendo bastante grande, entonces, ¿cuál es la diferencia en Guava? La clase HashMultiset se utiliza principalmente en Guava (ver más abajo).

   ArrayList<String> arrayList = Lists.newArrayList("a", "b", "c", "d", "a", "c");
   HashMultiset<String> multiset = HashMultiset.create(arrayList);
   multiset.elementSet().forEach(s -> System.out.println(s + ":" + multiset.count(s)));
   /**
    * result:
    * a:2
    * b:1
    * c:2
    * d:1
    */

Sí, siempre que agregue los elementos, no necesita preocuparse si se repiten o no. Finalmente, puede usar el método de conteo para contar el número de elementos repetidos. Con un aspecto cómodo y una escritura elegante, HashMultiset es una clase de Colección implementada en Guava, que puede contar fácilmente la cantidad de elementos.

  1. El valor uno a muchos es la colección de mapas de List. Suponiendo una escena en la que muchos animales deben clasificarse según sus tipos, creo que al final escribirás códigos similares. Escritura nativa de JDK:
   HashMap<String, Set<String>> animalMap = new HashMap<>();
   HashSet<String> dogSet = new HashSet<>();
   dogSet.add("旺财");
   dogSet.add("大黄");
   animalMap.put("狗", dogSet);
   HashSet<String> catSet = new HashSet<>();
   catSet.add("加菲");
   catSet.add("汤姆");
   animalMap.put("猫", catSet);
   System.out.println(animalMap.get("猫")); // [加菲, 汤姆]

La última línea de la consulta gato obtuvo "Garfield" y "Tom" en la categoría de gato. Este código es demasiado engorroso ¿Qué pasa con Guava?

   // use guava
   HashMultimap<String, String> multimap = HashMultimap.create();
   multimap.put("狗", "大黄");
   multimap.put("狗", "旺财");
   multimap.put("猫", "加菲");
   multimap.put("猫", "汤姆");
   System.out.println(multimap.get("猫")); // [加菲, 汤姆]

HashMultimap puede arrojar valores clave duplicados, y puede obtener todos los valores de valor cuando finalmente los obtenga. Puede ver que el resultado de salida es el mismo que el de la escritura JDK, pero el código es extremadamente refrescante.

Manipulación de cuerdas

Como el tipo de datos más comúnmente utilizado en el desarrollo, las mejoras en las operaciones de cadenas pueden hacer que el desarrollo sea más eficiente.

Empalme de personajes

De hecho, JDK 8 tiene un método de empalme de cadenas incorporado, pero es un empalme simple sin operaciones adicionales, como filtrar elementos nulos, eliminar espacios iniciales y finales, etc. Echemos un vistazo a varias formas de empalmar cadenas en JDK 8.

// JDK 方式一
ArrayList<String> list = Lists.newArrayList("a", "b", "c", null);
String join = String.join(",", list);
System.out.println(join); // a,b,c,null
// JDK 方式二
String result = list.stream().collect(Collectors.joining(","));
System.out.println(result); // a,b,c,null
// JDK 方式三
StringJoiner stringJoiner = new StringJoiner(",");
list.forEach(stringJoiner::add);
System.out.println(stringJoiner.toString()); // a,b,c,null

Puede ver que el valor nulo también se empalma en la cadena, que a veces no es lo que queremos, entonces, ¿cuál es la diferencia al usar Guava?

ArrayList<String> list = Lists.newArrayList("a", "b", "c", null);
String join = Joiner.on(",").skipNulls().join(list);
System.out.println(join); // a,b,c

String join1 = Joiner.on(",").useForNull("空值").join("旺财", "汤姆", "杰瑞", null);
System.out.println(join1); // 旺财,汤姆,杰瑞,空值

Puede ver que usando skipNulls () para omitir valores nulos, y useFornull (String) para personalizar el texto de visualización para valores nulos.

División de cadena

El JDK viene con la división de cadenas. Creo que debiste haberlo usado. Ese es el método de división de String. Pero este método tiene un problema. Si el último elemento está vacío, se descartará. Lo extraño es el primero El elemento está vacío pero no se descartará, lo cual es muy confuso. Demostremos este problema con un ejemplo.

String str = ",a,,b,";
String[] splitArr = str.split(",");
Arrays.stream(splitArr).forEach(System.out::println);
System.out.println("------");
/**
 *
 * a
 * 
 * b
 * ------
 */

También puede probarlo usted mismo, el último elemento no está vacío, simplemente desaparece.

¿Cómo funciona si usa guayaba? Guava proporciona la clase Splitter, y hay una serie de modos de operación para controlar intuitivamente la lógica de división.

String str = ",a ,,b ,";
Iterable<String> split = Splitter.on(",")
    .omitEmptyStrings() // 忽略空值
    .trimResults() // 过滤结果中的空白
    .split(str);
split.forEach(System.out::println);
/**
 * a
 * b
 */

Cache

En desarrollo, es posible que necesitemos usar una caché a pequeña escala para mejorar la velocidad de acceso. En este momento, la introducción de middleware de caché profesional puede parecer un desperdicio. Ahora está bien. Guava proporciona una clase de caché simple y puede caducar automáticamente los elementos agregados de acuerdo con la capacidad estimada, el tiempo de caducidad, etc. Aun así, tenemos que estimar el espacio de memoria que puede estar ocupado para evitar un uso excesivo de memoria.

Ahora echemos un vistazo a cómo usar el almacenamiento en caché en Guava.

@Test
public void testCache() throws ExecutionException, InterruptedException {

    CacheLoader cacheLoader = new CacheLoader<String, Animal>() {
        // 如果找不到元素,会调用这里
        @Override
        public Animal load(String s) {
            return null;
        }
    };
    LoadingCache<String, Animal> loadingCache = CacheBuilder.newBuilder()
        .maximumSize(1000) // 容量
        .expireAfterWrite(3, TimeUnit.SECONDS) // 过期时间
        .removalListener(new MyRemovalListener()) // 失效监听器
        .build(cacheLoader); //
    loadingCache.put("狗", new Animal("旺财", 1));
    loadingCache.put("猫", new Animal("汤姆", 3));
    loadingCache.put("狼", new Animal("灰太狼", 4));

    loadingCache.invalidate("猫"); // 手动失效

    Animal animal = loadingCache.get("狼");
    System.out.println(animal);
    Thread.sleep(4 * 1000);
    // 狼已经自动过去,获取为 null 值报错
    System.out.println(loadingCache.get("狼"));
    /**
     * key=猫,value=Animal{name='汤姆', age=3},reason=EXPLICIT
     * Animal{name='灰太狼', age=4}
     * key=狗,value=Animal{name='旺财', age=1},reason=EXPIRED
     * key=狼,value=Animal{name='灰太狼', age=4},reason=EXPIRED
     *
     * com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key 狼.
     */
}

/**
 * 缓存移除监听器
 */
class MyRemovalListener implements RemovalListener<String, Animal> {

    @Override
    public void onRemoval(RemovalNotification<String, Animal> notification) {
        String reason = String.format("key=%s,value=%s,reason=%s", notification.getKey(), notification.getValue(), notification.getCause());
        System.out.println(reason);
    }
}

class Animal {
    private String name;
    private Integer age;

    @Override
    public String toString() {
        return "Animal{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }

    public Animal(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

Este ejemplo se divide principalmente en CacheLoader, MyRemovalListener y LoadingCache.

El método de carga se reescribe en CacheLoader. Este método se llamará cuando el caché de consultas no obtenga un hit. Yo directamente devuelvo null aquí. De hecho, esto arrojará el CacheLoader devuelto nulo para el mensaje de excepción de clave cuando no hay hit.

MyRemovalListener es la clase de monitor cuando falla el elemento de la caché. El método onRemoval se llama automáticamente cuando falla la caché de elementos. Se debe tener en cuenta que este método es un método síncrono. Si toma mucho tiempo aquí, se bloqueará hasta que se complete el procesamiento.

LoadingCache es el objeto de operación principal de la caché, y los métodos put y get se utilizan comúnmente.

para resumir

Lo anterior introdujo funciones de Guava que creo que son las más utilizadas. Guava, como la biblioteca central de desarrollo de Java de código abierto de Google, personalmente siente que sigue siendo muy útil. Después de la introducción, no solo puede implementar rápidamente algunas funciones de uso común en el desarrollo, sino que también puede hacer que el código sea más elegante y conciso. Creo que se aplica a todos los proyectos de Java. También puede descubrir otras características de Guava por su cuenta. Su dirección de Github es: https://github.com/google/guava.

Supongo que te gusta

Origin blog.csdn.net/AI_mashimanong/article/details/109289274
Recomendado
Clasificación