Czy jest jakiś powód, dla którego leniwa inicjalizacja nie mogła zostać wbudowana w Javę?

10

Ponieważ pracuję na serwerze bez absolutnie żadnego nietrwałego stanu dla użytkowników, każdy obiekt związany z użytkownikiem jest wdrażany przy każdym żądaniu.

W rezultacie często robię leniwe inicjowanie właściwości obiektów, które mogą pozostać nieużywane.

protected EventDispatcher dispatcher = new EventDispatcher();

Staje się...

protected EventDispatcher<EventMessage> dispatcher;

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

Czy jest jakiś powód, dla którego nie można tego wbudować w Javę?

protected lazy EventDispatcher dispatcher = new EventDispatcher();


Jak wspomniano poniżej w komentarzach, zdaję sobie sprawę, że język może ewoluować teoretycznie i obejmować wszystko, co tylko chcesz. Szukam praktycznego pomiaru możliwości. Czy to koliduje z innymi funkcjami? Czy implementacja jest wystarczająco prosta, aby działała dobrze z istniejącą maszyną JVM? A nawet, czy to dobry pomysł?

Nicole
źródło
2
nie wiem, ale przykładowy kod nie jest bezpieczny dla wątków
Armand
2
@ Alison synchronizedsłowo kluczowe działałoby tak samo, jakby było w metodzie. Wyobrażam sobie, że byłoby miejsce na bardziej skomplikowane metody budowy. W moim konkretnym przypadku użycia, ze względu na charakter problemu, przy każdym żądaniu, ponieważ jest to jego własny świat, synchronizacja jest bezcelowa.
Nicole
W C # Lazy jest w bibliotece, ale jest obsługiwany przez język. sankarsan.wordpress.com/2009/10/04/laziness-in-c-4-0-lazyt Czy Java ma lambdas, delegatów i zamknięcia? Nawiasem mówiąc, chcesz zapytać o to na SO, aby Jon Skeet & co. mogą dzielić się swoją mądrością.
Job
3
Możesz zbudować prawie wszystko w dowolnym języku. Ale złożoność budżetu i lista funkcji są ograniczone, a projektanci języków mogą uwzględnić tylko to, co uważają za najważniejsze (no, z wyjątkiem Larry'ego Walla - zwłaszcza w Perlu 6, czyli „Wszystkie twoje paradygmaty należą do nas”).
1
Podstawowym problemem jest to, że Java jest jedynym statycznie typowanym językiem bez możliwości metaprogramowania. W C możesz napisać to jako makro w ciągu dziesięciu minut. W C ++ możesz napisać to jako szablon w około dwie minuty. W Javie możesz ... wklejać i modyfikować.
kevin cline

Odpowiedzi:

14

Oto ośmiostronicowa odpowiedź na twoje pytanie: http://tinlizzie.org/~awarth/papers/fool07.pdf

Jeśli mogę spróbować z grubsza streścić problemy z dodawaniem lenistwa, to są to przypadki narożne. Istnieje wiele zastrzeżeń dotyczących efektów ubocznych. Zastanów się, w twoim przykładzie, czy konstruktor miał widoczne skutki uboczne, takie jak uderzenie w globalny licznik lub wykonywanie operacji we / wy ... Trudno jest zrozumieć, kiedy to się stanie. Lub rozważ jeszcze brzydsze skutki uboczne związane z wyjątkami (są rzucane ... kiedy odwołujesz się do leniwego obiektu?)

Wystarczy przejść do sekcji 6 powyższego artykułu. (I podziwiaj całą logikę formalną systemu pisma na stronach, które pomijasz ...)

PT
źródło
Zaakceptowanie tej odpowiedzi ze względu na głębokość, z jaką papier odnosi się do tej funkcji. Dzięki!
Nicole,
TL; DR, gdy programujesz, musisz wiedzieć, co się dzieje, aby zapobiec skutkom ubocznym, z lenistwem, to może naprawdę pomóc. Jeśli znasz Hibernację i jak wiele osób ma z tym problem, po prostu wyobraź sobie to samo dla całego języka.
Walfrat,
10

Oczywiście jest to absolutnie możliwe. W rzeczywistości scala ma już dokładnie tę funkcję! (Scala jest językiem JVM i kompiluje się do kodu bajtowego). Oto fragment źródła Scala:

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

A oto jak wygląda pośrednia postać skompilowanego kodu:

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
źródło
Jak to się pogodzi z odpowiedzią PT na programmers.stackexchange.com/a/110958/24257 ?
Pacerier
6

Myślę, że najpierw musisz dodać prawdziwe właściwości do języka Java, zamiast polegać na idiomie getX / setX. W ten sposób możesz po prostu oznaczyć właściwość jako leniwą (i zsynchronizowaną, tylko do odczytu itp.).

Sortuj co jest proszony o tutaj (Objective-C, ale koncepcja dotyczy).

Martin Wickman
źródło
0

Oczywiście można to dodać do Javy, słowo kluczowe leniwe można zaimplementować jako cukier składniowy. Jednak to, czy zostanie ono wdrożone, zależy od wizji konstruktorów kompilatorów.

Michiel Overeem
źródło