Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

Esta es una publicación traducida por IA.

제이온

[Effective Java] Item 6. Evita la creación innecesaria de objetos

Seleccionar idioma

  • Español
  • English
  • 汉语
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Texto resumido por la IA durumis

  • Crear instancias de String o Boolean usando la palabra clave new es un desperdicio de memoria, por lo que es mejor declararlas como literales o usar el método Boolean.valueOf().
  • El método String.matches() usa expresiones regulares, por lo que puede haber problemas de rendimiento, y es mejor almacenar en caché las instancias de Pattern y reutilizarlas.
  • Cuando se devuelven objetos de vista, como el método keySet(), es más seguro usar una copia defensiva para devolver un nuevo objeto.

Cuando se crean objetos innecesarios

Usando new String()

String a = new String("hi");
String b = new String("hi");


Las cadenas a, b, c todas tendrán la cadena "hi". Sin embargo, dado que las direcciones a las que hacen referencia estas tres cadenas son diferentes, se produce un desperdicio al asignar memoria diferente para los mismos datos.


Untitled


Por lo tanto, al declarar una cadena, debe usar un literal en lugar de la palabra clave new.


String a = "hi";
String b = "hi";


El código fuente anterior usa solo una instancia. Además, al usar este método, se garantiza que todo el código que usa el literal de cadena "hi" dentro de la misma JVM reutilice el mismo objeto. Esto se debe a la característica de la agrupación de constantes de Java.


Usando new Boolean()

El código anterior crea una instancia de Boolean a través de un constructor que recibe una cadena como parámetro. Boolean solo puede ser true o false, y crear una instancia cada vez es una pérdida de memoria. Por lo tanto, es mejor usar el método de fábrica estático Boolean.valueOf().



Usando String.matches()

Si el costo de creación es alto, es mejor almacenarlo en caché y reutilizarlo, pero no siempre podemos saber el costo del objeto que estamos creando. Por ejemplo, si queremos escribir un método que verifique si una cadena dada es un número romano válido, el uso de expresiones regulares es la forma más fácil, como se muestra a continuación.


public static boolean isRomanNumeral(String s) {
    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");


Sin embargo, String.matches() es un método problemático en términos de rendimiento. La instancia de Pattern creada internamente por este método para la expresión regular se utiliza una vez y se descarta, convirtiéndose inmediatamente en un objetivo de la recolección de basura, pero a medida que aumenta la frecuencia con la que se utiliza la expresión regular en particular, el costo de crear y descartar la misma instancia de Pattern aumenta. Por lo tanto, es mejor almacenar en caché la instancia de Pattern por adelantado y reutilizarla cada vez que se llame al método isRomanNumeral() más adelante.


public class RomanNumerals {

    private static final Pattern ROMAN = Pattern.compile(
        "^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    public static boolean isRomanNumeral(String s) {
        return ROMAN.matcher(s).matches();
    }


Nota

En todos los ejemplos anteriores, cuando se almacenaba en caché un objeto innecesario, todos se crearon como objetos inmutables. Esto se debe a que es seguro reutilizarlos. Sin embargo, hay casos en los que la reutilización contradice la intuición de los objetos inmutables.


Un adaptador (vista) es un objeto que delega el trabajo real a un objeto de back-end y actúa como una segunda interfaz. Un adaptador solo necesita administrar el objeto de back-end, por lo que solo necesita crear un adaptador por cada objeto de back-end.


Por ejemplo, el método keySet() de la interfaz Map devuelve una vista Set que contiene todas las claves dentro del objeto Map. Los usuarios pueden pensar que se crea una nueva instancia de Set cada vez que se llama al método keySet(), pero al ver el código de implementación real de JDK, devuelve la misma instancia de Set variable cada vez.


Esto se debe a que incluso si la instancia de Set devuelta es variable, la función que realiza es la misma, y todas las instancias de Set representan la instancia de Map. Por lo tanto, no importa si keySet() crea varias vistas de objetos, pero no hay necesidad ni beneficio.


public class UsingKeySet {

    public static void main(String[] args) {
        Map menu = new HashMap<>();
        menu.put("Burger", 8);
        menu.put("Pizza", 9);

        Set names1 = menu.keySet();
        Set names2 = menu.keySet();

        names1.remove("Burger");
        System.out.println(names1.size()); // 1
        System.out.println(names2.size()); // 1
    }


Por lo tanto, si modifica la instancia names1, la instancia names2 también se verá afectada.


Sin embargo, personalmente creo que el valor devuelto por el método keySet() debe usar una copia defensiva para devolver un nuevo objeto cada vez. Si la instancia de Set recibida por el método keySet() también se está utilizando en otro lugar y hay código que cambia el estado de esta instancia, ya no podrá confiar en el valor de la instancia de Set y la instancia de Map.


Además, a menos que el método keySet() se use excesivamente, el hecho de que la interfaz Set se cree cada vez no afectará fatalmente al rendimiento. Creo que es mejor hacer que la interfaz Set sea un objeto inmutable para que se pueda mantener de forma estable y segura.


Autoboxing

El autoboxing es una técnica que convierte automáticamente entre tipos de datos primitivos y tipos de envoltura cuando el programador usa ambos tipos de datos de forma mixta. Sin embargo, el autoboxing solo desdibuja la distinción entre tipos de datos primitivos y tipos de envoltura, no los elimina por completo.


public static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
    return sum;


Lógicamente no hay problema, pero es un código muy ineficiente en términos de rendimiento. La razón es el tipo de sum y el tipo de i dentro del ciclo for.


El tipo de sum es Long, y i es long. Es decir, cada vez que i, que es de tipo long, se suma a sum durante la iteración del bucle, se crea una nueva instancia de Long. Como resultado, es necesario utilizar tipos de datos primitivos en lugar de tipos de envoltura y tener cuidado para evitar el autoboxing no deseado.


Puntos que no deben malinterpretarse

No debe malinterpretarse que la necesidad de evitar la creación de objetos innecesarios se debe simplemente al alto costo de la creación de objetos.


Especialmente en las JVM modernas, crear y recuperar objetos pequeños innecesariamente no es una tarea tan costosa. Por lo tanto, a menos que sean objetos muy costosos como las conexiones a bases de datos, no cree un grupo de objetos personalizado.


Además, recuerde que el daño de reutilizar objetos cuando se necesita una copia defensiva es mucho mayor que el daño de crear objetos innecesarios repetidamente. Los efectos secundarios de la creación repetida solo afectan la forma del código y el rendimiento, pero si la copia defensiva falla, irá directamente a errores y problemas de seguridad.


Fuente

제이온
제이온
제이온
제이온
[Effective Java] Item 5. Utilice la inyección de dependencia en lugar de especificar recursos Si una clase depende de recursos externos, es mejor no usar singletons ni clases de utilidad estáticas. La inyección de dependencia puede mejorar la flexibilidad, la reutilización y la facilidad de prueba de la clase, y el uso del patrón de método de fábr

28 de abril de 2024

[Effective Java] Item 2. Considere un constructor si el constructor tiene muchos parámetros Al crear objetos con muchos parámetros, el uso del patrón de constructor puede hacer que el código sea más limpio y fácil de leer. Cree un objeto de constructor con parámetros obligatorios y configure los parámetros opcionales con el método setter, luego

27 de abril de 2024

[Java] Colección sincronizada vs Colección concurrente Analicé comparativamente las diversas formas y ventajas y desventajas para resolver los problemas de sincronización cuando se utiliza una colección en un entorno multihilo en Java. Vector, Hashtable, Collections.synchronizedXXX y otras colecciones sincron

25 de abril de 2024

[Javascript] Estructura de objetos (V8) El objeto JavaScript en el motor V8 se optimiza como una estructura, según el estado, en un modo rápido y se convierte en un modo de diccionario que funciona como un mapa hash. El modo rápido es rápido cuando la clave y el valor son casi fijos, pero cuand
곽경직
곽경직
곽경직
곽경직
곽경직

18 de marzo de 2024

[Concurrencia] Operación atómica: Memory Fence y Memory Ordering Esta publicación de blog explica cómo tener en cuenta el orden de la memoria en las operaciones atómicas y la importancia de las opciones de ordenación. Se explica en detalle las diversas opciones de ordenación, como Relaxed, Acquire, Release, AcqRel y Se
곽경직
곽경직
곽경직
곽경직
곽경직

12 de abril de 2024

Modelado de datos físico El modelado de datos físico es el proceso de diseñar las tablas de una base de datos relacional para que sean realmente utilizables. Se busca optimizar el rendimiento mediante la eficiencia del espacio de almacenamiento, el particionamiento de datos, el d
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

9 de abril de 2024

[Next.js] Inyección de entorno de tiempo de ejecución Descubre cómo configurar variables de entorno en Next.js después del tiempo de compilación. Te mostramos cómo instalar cross-env y modificar los scripts para que los usuarios de Windows también puedan seguirlos fácilmente. Este método se puede utilizar pa
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

20 de marzo de 2024

3 cosas que quiero decirle a los inversores individuales que están comenzando en las acciones Este es un consejo sobre la estrategia de inversión de valor y una actitud positiva para los inversores individuales que están comenzando a invertir en acciones. La inversión de valor es una estrategia que busca oportunidades de compra en el corto plazo c
고집스런가치투자
고집스런가치투자
고집스런가치투자
고집스런가치투자

3 de abril de 2024

[No especializado en informática, sobrevivir como desarrollador] 14. Resumen de las preguntas comunes de la entrevista técnica para desarrolladores principiantes Esta es una guía de preparación para entrevistas técnicas para desarrolladores principiantes. Se explican conceptos que aparecen con frecuencia en las entrevistas, como el área de memoria principal, las estructuras de datos, RDBMS y NoSQL, orientación a p
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 de abril de 2024