Y a-t-il une raison pour laquelle l'initialisation paresseuse n'a pas pu être intégrée à Java?

10

Comme je travaille sur un serveur sans aucun état non persistant pour les utilisateurs, chaque objet lié à l'utilisateur que nous avons est déployé à chaque demande.

Par conséquent, je me retrouve souvent à faire une initialisation paresseuse de propriétés d'objets qui peuvent rester inutilisés.

protected EventDispatcher dispatcher = new EventDispatcher();

Devient...

protected EventDispatcher<EventMessage> dispatcher;

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

Y a-t-il une raison pour laquelle cela n'a pas pu être intégré à Java?

protected lazy EventDispatcher dispatcher = new EventDispatcher();


Comme mentionné ci-dessous dans les commentaires, je me rends compte qu'un langage pourrait théoriquement évoluer pour inclure presque tout ce que vous voulez. Je cherche une mesure pratique de possibilité. Serait-ce en conflit avec d'autres fonctionnalités? L'implémentation est-elle assez simple pour bien fonctionner avec la JVM telle qu'elle existe? Et même, est-ce une bonne idée?

Nicole
la source
2
ne sais pas mais l'exemple de code n'est pas thread-safe
Armand
2
@Alison, le synchronizedmot - clé fonctionnerait de la même manière que s'il figurait sur la méthode. J'imagine qu'il y aurait une certaine adaptation à des méthodes de construction plus compliquées. Dans mon cas d'utilisation spécifique , en raison de la nature du problème, avec chaque demande comme son propre monde, la synchronisation est inutile.
Nicole
En C #, Lazy est dans une bibliothèque, mais il est pris en charge par le langage. sankarsan.wordpress.com/2009/10/04/laziness-in-c-4-0-lazyt Java a-t-il des lambdas et des délégués et des fermetures? Soit dit en passant, vous voulez poser cette question sur SO, afin que Jon Skeet & co. peuvent partager leur sagesse.
Job
3
Vous pouvez construire à peu près tout dans n'importe quelle langue. Mais le budget de complexité et la liste des fonctionnalités sont limités et les concepteurs de langage ne peuvent inclure que ce qu'ils considèrent comme le plus important (enfin, sauf Larry Wall - en particulier dans Perl 6 alias "Tous vos paradigmes nous appartiennent.").
1
Le problème fondamental est que Java est à peu près le seul langage de type statique sans installation de méta-programmation. En C, vous pouvez écrire ceci sous forme de macro en dix minutes. En C ++, vous pouvez écrire ceci en tant que modèle en environ deux minutes. En Java, vous pouvez ... coller et modifier.
Kevin Cline,

Réponses:

14

Voici une réponse de huit pages à votre question: http://tinlizzie.org/~awarth/papers/fool07.pdf

Si je peux essayer de résumer grossièrement les problèmes d'ajout de paresse, ce sont les cas d'angle. Il y a beaucoup de mises en garde concernant les effets secondaires. Considérez, dans votre exemple, si le constructeur a eu des effets secondaires visibles, comme heurter un compteur global ou faire des E / S ... Il est difficile de savoir quand cela se produira. Ou considérez des effets secondaires encore plus moches sur les exceptions (ils sont levés ... lorsque vous faites référence à l'objet paresseux?)

Passez simplement à la section 6 du document ci-dessus. (Et admirez toute la logique formelle du système de type sur les pages que vous sautez ...)

PT
la source
Accepter cette réponse en raison de la profondeur avec laquelle le document traite de cette fonctionnalité. Merci!
Nicole
TL; DR lorsque vous programmez, vous devez savoir ce qui se passe pour prévenir les effets secondaires, avec la paresse, cela peut vraiment vous échapper. Si vous connaissez Hibernate et combien de problèmes certaines personnes ont avec cela, imaginez simplement la même chose pour toute la langue.
Walfrat
10

Bien sûr, c'est éminemment possible. En fait, scala a déjà exactement cette fonctionnalité! (Scala est un langage JVM et se compile en bytecode). Voici un morceau de source scala:

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

Et voici à quoi ressemble une forme intermédiaire du code compilé:

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

}

oxbow_lakes
la source
Alors, comment cela se concilierait-il avec la réponse de PT sur programmers.stackexchange.com/a/110958/24257 ?
Pacerier
6

Je pense que vous devez d'abord ajouter des propriétés réelles à la jauge Java, plutôt que de vous fier à l'idiome getX / setX. De cette façon, vous pouvez simplement marquer la propriété comme paresseuse (et synchronisée, en lecture seule, etc.).

Sorte de ce qui est demandé ici (Objectif-C, mais le concept s'applique).

Martin Wickman
la source
0

Bien sûr, cela pourrait être ajouté à Java, le mot-clé paresseux pourrait être implémenté comme sucre syntaxique. Cependant, sa mise en œuvre dépendra de la vision des constructeurs du compilateur.

Michiel Overeem
la source