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

Questo è un post tradotto da IA.

제이온

[Effictive Java] Item 6. Evitare la creazione di oggetti non necessari

Seleziona la lingua

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

Testo riassunto dall'intelligenza artificiale durumis

  • Creare istanze di stringhe o Boolean usando la parola chiave new è uno spreco di memoria, quindi è meglio dichiararle come letterali o usare il metodo Boolean.valueOf().
  • Il metodo String.matches() usa le espressioni regolari, quindi può causare problemi di prestazioni. È meglio mettere in cache l'istanza di Pattern e riutilizzarla.
  • Quando si restituisce un oggetto di visualizzazione, come il metodo keySet(), è più sicuro usare la copia difensiva per restituire un nuovo oggetto.

Quando si creano oggetti superflui

Utilizzo di new String()

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


Le stringhe a, b e c avranno tutte la stringa "hi". Tuttavia, poiché gli indirizzi a cui questi tre stringhe fanno riferimento sono tutti diversi, si verifica uno spreco in termini di allocazione di memoria separata per gli stessi dati.


Untitled


Pertanto, quando si dichiarano le stringhe, è necessario utilizzare i letterali invece della parola chiave new.


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


Il codice sorgente precedente utilizza una sola istanza. Inoltre, l'utilizzo di questo metodo garantisce che tutti i codici che utilizzano il letterale di stringa "hi" nello stesso JVM riutilizzino lo stesso oggetto. Questo è dovuto alla caratteristica del pool di costanti Java.


Utilizzo di new Boolean()

Il codice precedente sta creando un'istanza Boolean utilizzando il costruttore che accetta una stringa come parametro. Boolean può essere solo true o false, quindi la creazione di un'istanza ogni volta è uno spreco di memoria. Pertanto, è meglio utilizzare il metodo di fabbrica statico Boolean.valueOf().



Utilizzo di String.matches()

È meglio memorizzare nella cache e riutilizzare gli oggetti costosi da creare, ma non sempre sappiamo il costo degli oggetti che creiamo. Ad esempio, se volessimo scrivere un metodo per verificare se una stringa data è un numero romano valido, il modo più semplice sarebbe quello di utilizzare un'espressione regolare come la seguente.


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})$");


Tuttavia, String.matches() è un metodo con problemi di prestazioni. L'istanza Pattern utilizzata internamente da questo metodo per l'espressione regolare viene creata una sola volta e quindi eliminata, diventando immediatamente un obiettivo per la garbage collection. Se la frequenza di utilizzo di questa espressione regolare aumenta, il costo di creazione ed eliminazione della stessa istanza Pattern aumenta. Pertanto, è meglio memorizzare nella cache l'istanza Pattern in anticipo e riutilizzarla ogni volta che il metodo isRomanNumeral() viene chiamato.


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();
    }


Attenzione

In tutti gli esempi precedenti, abbiamo reso immutabili tutti gli oggetti memorizzati nella cache per evitare la creazione di oggetti inutili. Questo perché è sicuro riutilizzarli. Tuttavia, ci sono casi in cui questo è in contrasto con l'intuizione di riutilizzare gli oggetti immutabili.


Gli adattatori (viste) sono oggetti che delegano il lavoro effettivo agli oggetti sottostanti e fungono da seconda interfaccia. Gli adattatori devono solo gestire gli oggetti sottostanti, quindi è sufficiente creare un solo adattatore per ogni oggetto sottostante.


Ad esempio, il metodo keySet() dell'interfaccia Map restituisce una vista Set di tutte le chiavi all'interno dell'oggetto Map. Si potrebbe pensare che una nuova istanza Set venga creata ogni volta che si chiama il metodo keySet(), ma se si guarda effettivamente l'implementazione del JDK, viene restituita la stessa istanza Set variabile ogni volta.


Questo perché tutte le istanze Set svolgono la stessa funzione, anche se l'istanza Set restituita è variabile, e tutte le istanze Set rappresentano l'istanza Map. Pertanto, non importa se keySet() crea più oggetti vista, ma non c'è bisogno né 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
    }


Pertanto, se si modifica l'istanza names1 come sopra, anche l'istanza names2 ne risentirà.


Tuttavia, personalmente credo che il valore restituito dal metodo keySet() dovrebbe utilizzare la copia difensiva per restituire un nuovo oggetto ogni volta. Se l'istanza Set ricevuta dal metodo keySet() viene utilizzata anche in altri punti e c'è del codice che cambia lo stato di questa istanza, non saremmo più certi dello stato corrente dell'istanza Set e dell'istanza Map.


Inoltre, a meno che l'ambiente non utilizzi eccessivamente keySet(), il fatto che l'interfaccia Set venga creata ogni volta non influisce in modo sostanziale sulle prestazioni. Penso che sia meglio rendere l'interfaccia Set immutabile per mantenere la stabilità della manutenzione.


Autoboxing

L'autoboxing è una tecnica che converte automaticamente i tipi primitivi e i tipi wrapper tra loro quando un programmatore li mescola. Tuttavia, l'autoboxing non elimina completamente la distinzione tra tipi primitivi e wrapper.


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


Logicamente non ci sono problemi, ma il codice è molto inefficiente in termini di prestazioni. Questo è dovuto al tipo di sum e al tipo di i all'interno del ciclo for.


Il tipo di sum è Long, mentre il tipo di i è long. Ciò significa che il tipo long di i creerà una nuova istanza Long ogni volta che verrà aggiunto a sum durante il ciclo. Di conseguenza, è necessario utilizzare i tipi primitivi invece dei tipi wrapper e fare attenzione a evitare l'autoboxing non intenzionale.


Cosa non va interpretato male

Non si deve pensare che evitare la creazione di oggetti inutili significhi semplicemente che il costo della creazione di oggetti è elevato e quindi va evitato.


Soprattutto nella JVM di oggi, la creazione ed eliminazione di piccoli oggetti inutili non è un compito così impegnativo. Pertanto, a meno che non si tratti di oggetti molto costosi come le connessioni al database, non creare un pool di oggetti personalizzato.


Inoltre, ricordare che i danni causati dal riutilizzo di oggetti in situazioni in cui è necessaria una copia difensiva sono molto più grandi dei danni causati dalla creazione ripetuta di oggetti inutili. Gli effetti collaterali della creazione ripetuta influiscono solo sulla forma del codice e sulle prestazioni, mentre il fallimento della copia difensiva porta direttamente a bug e problemi di sicurezza.


Fonti

제이온
제이온
제이온
제이온
[Effective Java] Item 1. Consider static factory methods instead of constructors I metodi di fabbrica statici sono un modo flessibile ed efficiente per creare istanze invece di costruttori. Possono avere un nome, restituire istanze che soddisfano determinate condizioni e migliorare le prestazioni tramite il caching. A differenza del m

27 aprile 2024

[Effettivi Java] Elemento 5. Non dichiarare risorse, utilizzare l'iniezione di dipendenze Se una classe dipende da risorse esterne, è meglio non utilizzare classi di utilità statiche o singleton. L'iniezione di dipendenze può migliorare la flessibilità, la riusabilità e la facilità di test della classe, e l'utilizzo del pattern di metodo di fa

28 aprile 2024

[Java] Synchronized Collection vs Concurrent Collection In Java, we compared and analyzed various methods and advantages and disadvantages for solving synchronization problems when using collections in a multithreaded environment. We introduce the characteristics and performance differences of synchronized col

25 aprile 2024

[Javascript] Struttura dell'oggetto (V8) L'oggetto JavaScript in V8 Engine viene ottimizzato come una struttura in base allo stato e convertito in modalità Fast e modalità Dictionary che funziona come una hashmap. La modalità Fast è rapida con chiave e valore in un formato quasi fisso, ma se vie
곽경직
곽경직
곽경직
곽경직
곽경직

18 marzo 2024

[Concurrency] Operazione Atomica: Memory Fence e Memory Ordering Questo post del blog spiega come considerare l'ordine di memoria nelle operazioni atomiche e l'importanza delle opzioni di ordinamento. Vengono spiegate le diverse opzioni di ordinamento come Relaxed, Acquire, Release, AcqRel, SecCst, insieme ai vantaggi
곽경직
곽경직
곽경직
곽경직
곽경직

12 aprile 2024

[Non specialisti, sopravvivere come sviluppatori] 14. Riepilogo dei contenuti del colloquio tecnico per sviluppatori junior Questa è una guida alla preparazione ai colloqui tecnici per sviluppatori junior. Copre argomenti come la memoria principale, le strutture dati, RDBMS e NoSQL, programmazione procedurale e orientata agli oggetti, override e overload, algoritmi di sostituz
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 aprile 2024

[Non laureati, sopravvivere come sviluppatori] 16. Suggerimenti per la creazione di un portfolio per sviluppatori junior Uno sviluppatore junior (soprattutto se non ha un background tecnico) deve descrivere chiaramente i servizi o le funzionalità sviluppate nel portfolio, oltre alle competenze tecniche. Ad esempio, per un progetto di "Comunità per studenti in cerca di lavor
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 aprile 2024

Come Rust impedisce i bug di concorrenza Rust è un linguaggio potente che affronta le sfide della programmazione concorrente. Il suo sistema di tipi e il modello di proprietà garantiscono la sicurezza nella condivisione e nel trasferimento di dati tra thread. Tramite pattern di mutabilità intern
곽경직
곽경직
곽경직
곽경직
곽경직

28 marzo 2024

[Non-major, sopravvivere come sviluppatore] 7. Cosa aiuta e cosa no quando si cerca un lavoro nel settore Quando ci si prepara a cercare lavoro come sviluppatore, il blog tecnologico è inefficiente, mentre GitHub è consigliato per la gestione dei progetti e la condivisione del codice sorgente. Tra le varie certificazioni, è consigliabile preparare l'esame per
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

29 marzo 2024