C'è qualche motivo per cui l'inizializzazione lenta non può essere integrata in Java?


10

Dal momento che sto lavorando su un server senza stato assolutamente non persistente per gli utenti, ogni oggetto relativo all'utente che abbiamo è implementato su ogni richiesta.

Di conseguenza, spesso mi ritrovo a eseguire un'inizializzazione pigra delle proprietà degli oggetti che potrebbero non essere utilizzate.

protected EventDispatcher dispatcher = new EventDispatcher();

Diventa ...

protected EventDispatcher<EventMessage> dispatcher;

public EventDispatcher<EventMessage> getEventDispatcher() {
    if (dispatcher == null) {
        dispatcher = new EventDispatcher<EventMessage>();
    }
    return dispatcher;
}

C'è qualche motivo per cui questo non può essere integrato in Java?

protected lazy EventDispatcher dispatcher = new EventDispatcher();


Come menzionato di seguito nei commenti, mi rendo conto che una lingua potrebbe teoricamente evolversi per includere quasi tutto ciò che desideri. Sto cercando una misura pratica della possibilità. Questo conflitto con altre funzionalità? L'implementazione è abbastanza semplice da funzionare bene con la JVM così com'è? E anche, è una buona idea?


2
non so ma il codice di esempio non è thread-safe
Armand,

2
@Alison la synchronizedparola chiave funzionerebbe come se fosse sul metodo. Immagino che ci sarebbe qualche accomodamento di metodi di costruzione più complicati. Nel mio caso d'uso specifico , a causa della natura del problema, con ogni richiesta come il suo mondo, la sincronizzazione è inutile.
Nicole,

In C # Lazy è in una libreria, ma è supportato dalla lingua. sankarsan.wordpress.com/2009/10/04/laziness-in-c-4-0-lazyt Java ha lambda, delegati e chiusure? A proposito, vuoi chiedere questo su SO, in modo che Jon Skeet & co. possono condividere la loro saggezza.
Giobbe

3
Puoi costruire praticamente tutto in qualsiasi lingua. Ma il budget di complessità e l'elenco delle funzionalità sono limitati e i progettisti del linguaggio possono includere solo ciò che considerano più importante (beh, tranne Larry Wall - specialmente in Perl 6 aka "Tutti i tuoi paradigmi ci appartengono").

1
Il problema fondamentale è che Java riguarda l'unico linguaggio tipicamente statico senza funzionalità di meta-programmazione. In C potresti scrivere questo come macro in dieci minuti. In C ++ potresti scrivere questo come modello in circa due minuti. In Java puoi ... incollare e modificare.
Kevin Cline,

Risposte:


14

Ecco una risposta di otto pagine alla tua domanda: http://tinlizzie.org/~awarth/papers/fool07.pdf

Se posso provare e sintetizzare grossolanamente i problemi con l'aggiunta di pigrizia, sono i casi d'angolo. Ci sono molti avvertimenti sugli effetti collaterali. Considera, nel tuo esempio, se il costruttore avesse effetti collaterali visibili come urtare un contatore globale o fare I / O ... È difficile ragionare su quando ciò accadrà. O considerare effetti collaterali ancora più brutti sulle eccezioni (vengono lanciati ... quando fai riferimento all'oggetto pigro?)

Passa alla sezione 6 del documento sopra. (E ammira tutta la logica formale del sistema di tipi nelle pagine che salti ...)


Accettare questa risposta a causa della profondità con cui la carta affronta questa funzione. Grazie!
Nicole,

TL; DR quando programmate devi sapere cosa succede per prevenire gli effetti collaterali, con la pigrizia, questo può davvero togliersi di mano. Se conosci Hibernate e quanti problemi hanno alcune persone con esso, immagina lo stesso per l'intera lingua.
Walfrat

10

Certo, è eminentemente possibile. In effetti, Scala ha già esattamente questa funzione! (Scala è un linguaggio JVM e compila fino al bytecode). Ecco un pezzo di scala fonte:

class Foo {
  lazy val bar = "Hello World"
}

Ed ecco come appare una forma intermedia del codice compilato:

scalac -Xprint:icode Foo.scala

[[syntax trees at end of icode]]// Scala source: Foo.scala
package <empty> {
  class Foo extends java.lang.Object with ScalaObject {
    @volatile protected var bitmap$0: Int = 0;
    lazy private[this] var bar: java.lang.String = _;
    <stable> <accessor> lazy def bar(): java.lang.String = {
      if (Foo.this.bitmap$0.&(1).==(0))
        {
          Foo.this.synchronized({
            if (Foo.this.bitmap$0.&(1).==(0))
              {
                Foo.this.bar = "Hello World";
                Foo.this.bitmap$0 = Foo.this.bitmap$0.|(1);
                ()
              };
            scala.runtime.BoxedUnit.UNIT
          });
          ()
        };
      Foo.this.bar
    };
    def this(): Foo = {
      Foo.super.this();
      ()
    }
  }

}


In che modo questo si conciliava con la risposta di PT su programmers.stackexchange.com/a/110958/24257 ?
Pacerier,

6

Penso che prima devi aggiungere proprietà reali al linguaggio Java, piuttosto che fare affidamento sul linguaggio getX / setX. In questo modo potresti semplicemente contrassegnare la proprietà come pigra (e sincronizzata, di sola lettura ecc ...).

Sorta di ciò che viene richiesto qui (Obiettivo-C, ma si applica il concetto).


0

Naturalmente questo potrebbe essere aggiunto a Java, la parola chiave lazy potrebbe essere implementata come zucchero sintattico. Tuttavia, se verrà implementato dipende dalla visione dei costruttori di compilatori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.