Co same w sobie oznaczają nawiasy klamrowe w Javie?

79

Mam kod Java, który używa nawiasów klamrowych na dwa sposoby

// Curly braces attached to an 'if' statement:
if(node.getId() != null)
{
    node.getId().apply(this);
}

// Curly braces by themselves:
{
    List<PExp> copy = new ArrayList<PExp>(node.getArgs());
    for(PExp e : copy)
    {
        e.apply(this);
    }
}
outAMethodExp(node);

Co oznaczają te samodzielne nawiasy klamrowe po pierwszym ifzdaniu?

Paul Wicks
źródło

Odpowiedzi:

120

Jedynym celem dodatkowych nawiasów klamrowych jest zapewnienie ograniczenia zakresu. List<PExp> copyBędzie istnieć tylko w tych szelek, a nie będzie miał zakres poza nimi.

Jeśli jest to wygenerowany kod, zakładam, że generator kodu robi to, aby mógł wstawić kod (taki jak ten) bez martwienia się o to, ile razy wstawił List<PExp> copyi bez martwienia się o ewentualną zmianę nazw zmiennych, jeśli ten fragment jest wstawiany do tej samej metody więcej niż raz.

matowe b
źródło
9
Dodatkową „korzyścią” w tym przypadku jest to, że copymożna je odrzucić przed outAMethodExp()zwrotem. Jeśli jest to połączenie długotrwałe lub wymagające dużej ilości pamięci, może to być pomocne. Umieściłem „korzyść” w cudzysłowie, ponieważ refaktoryzacja na oddzielne metody jest generalnie dużo czystsza i bardziej przejrzysta niż korzystanie z tej składni.
dimo414
1
W rzeczywistości określanie zakresu zmiennej nie ma wpływu na czyszczenie pamięci. We wszystkich nowoczesnych maszynach JVM, które znam, JIT może określić, że obiekt kwalifikuje się do GC niezależnie od obecności lub braku konstrukcji określania zakresu, takich jak nawiasy klamrowe.
Daniel Pryden
27

Po drugie, co napisał Matt b i dodam, że innym zastosowaniem anonimowych nawiasów klamrowych, jakie widziałem, jest deklarowanie niejawnego konstruktora w klasach anonimowych. Na przykład:

  List<String> names = new ArrayList<String>() {
    // I want to initialize this ArrayList instace in-line,
    // but I can't define a constructor for an anonymous class:
      {
        add("Adam");
        add("Eve");
      }

  };

Niektóre frameworki do testowania jednostkowego przeniosły tę składnię na inny poziom, co pozwala na działanie sprytnych rzeczy, które wyglądają na całkowicie niekompilowalne. Ponieważ wyglądają na nieznane, sam nie jestem takim wielkim fanem, ale warto przynajmniej rozpoznać, co się dzieje, jeśli natkniesz się na takie użycie.

Dov Wasserman
źródło
Przepraszam, nie rozumiem tego kodu. Czy „dodaje” klasę lub funkcję. Jeśli jest to funkcja: do jakiej klasy należy? Czy w tym przypadku ArrayList akceptuje typ delegata?
Peter Mortensen
7
„add” to funkcja. Elementy w nawiasach klamrowych są wywoływane przed konstruktorem w celu wykonania wstępnej inicjalizacji. Możesz sprawdzić c2.com/cgi/wiki?DoubleBraceInitialization, aby uzyskać więcej.
Zaven Nahapetyan
1
Technicznie rzecz biorąc, konstruktor jest wywoływany jako pierwszy, a blok inicjalizacji instancji jest wywoływany natychmiast po wywołaniu funkcji super(...).
Oli
8

Zgadzam się z odpowiedzią limit zakresu, ale dodałbym jedną rzecz.

Czasami widzisz taką konstrukcję w kodzie ludzi, którzy lubią składać sekcje swojego kodu i mają edytory, które automatycznie składają nawiasy klamrowe. Używają go do składania swojego kodu w sekcje logiczne, które nie należą do funkcji, klasy, pętli itp., Które zwykle byłyby zwinięte.

Eli
źródło
4

Właściwie to domyślam się, że ktoś zapomniał innego stwierdzenia.

Rzadko jest dobry powód, aby zawracać sobie głowę tworzeniem dodatkowych zakresów blokowych. W tym iw większości przypadków jest o wiele bardziej prawdopodobne, że ktoś zapomniał wpisać oświadczenie kontrolne, niż że robił coś sprytnego.

Patrick
źródło
2
Głosuję na ciebie po prostu dlatego, że może się to zdarzyć, stało się, a Occam toczy się w grobie, ponieważ zostałeś odrzucony. :)
willasaywhat
1
Jest generowany przez SableCC. Stawiam 5 $, o których nie zapomnieli
Pavel Feldman
Dodatkowe nawiasy klamrowe są przydatne, aby zapobiec wkradaniu się do ciebie zmiennych globalnych w długiej metodzie, w której chcesz przechowywać kilka podobnych bloków kodu w tym samym miejscu, gdzie bloki nie są wystarczająco złożone, aby uzasadniać nowe metody.
jayunit100
Zaznaczam zajęcia z języka Java na uniwersytecie i widzę, że często jest to dokładny powód, dla którego znajduje się w kodzie. Podczas ponownego rozkładania na czynniki ludzie czasami wycinają / wklejają, a następnie widzą niewłaściwą liczbę nawiasów klamrowych… po prostu dodaj jeden… i zobacz, co otrzymałeś. Z tego powodu głosuję w tym głosowaniu. Nie zawsze jest to inne stwierdzenie, ale często jest to zwykły błąd.
ThePerson,
Głosowałem za tobą, ponieważ -1 głosów oznacza, że ​​nie powinieneś nawet brać udziału. Może nie wiedziałeś, ale włożyłeś wysiłek. Nie chodzi mi o trofea dla wszystkich, ale „dziękuję” to tylko to, co mówię ludziom, którzy próbują pomóc. (+1 == dzięki).
user426364
2

Tworzą wewnętrzny zakres. Zmienna zadeklarowana w tych nawiasach klamrowych nie jest widoczna poza nimi. Dotyczy to również C / C ++.

Paweł Hajdan
źródło
1

Nawiasy klamrowe są również przydatne do zmniejszania zakresu w instrukcjach switch / case.

switch(foo) {
  case BAR:
     int i = ...
     ...
  case BAZ:
     int i = ... // error, "i" already defined in scope
}

Ale możesz pisać

switch(foo) {
  case BAR:{
     int i = ...
     ...
  }
  case BAZ:{
     int i = ... // OK
  }
}
Philipp
źródło
1

Jest również używany do bloków inicjalizacyjnych .

Gabriel
źródło
Chyba warto wspomnieć, że dotyczy to tylko inicjalizacji klasy statycznej poza konstruktorem. Fragment kodu OP znajduje się w bloku metody (tylko możliwe miejsce na to).
mmoore,
Blok inicjalizacji jest dla statycznego inicjowania klasy, jeśli jest poprzedzony staticprzeciwnym razie jego instancja bloku inicjalizacji.
Gabriel
Prawdziwe opowieści. Dziękuję za wyjaśnienie.
mmoore,
0

Definiują nowy zakres, co oznacza, że ​​wszystko zadeklarowane w tym zakresie nie jest widoczne poza nawiasami klamrowymi.

fhe
źródło
0

Co ciekawe: nawiasy klamrowe faktycznie włączają klasę instrukcji: deklaracje.

To jest nielegalne: if(a) int f;

ale to jest legalne: if(a) { int f; }

Hugo
źródło
Dokładnie ten kod jest bezużyteczny, nie będzie można zobaczyć f poza nawiasami klamrowymi. Aby go użyć, musisz zadeklarować i używać go w tym samym zakresie. Potrzebujesz więc więcej niż jednej instrukcji, więc potrzebujesz nawiasów klamrowych.
Pavel Feldman
o to chodzi w sprawdzaniu kompilatora, o którym wspominam. Uważam za interesujące, że istnieje różnica w „ukrytym zakresie” (który uważam za każdy wiersz bez nawiasów klamrowych) i jawnymi. Łatwo zapomnieć, że kompilator może coś zmienić.
Hugo
A co jeśli (userWantsTocInReport) {new Toc (report};}? Nie mówię, że to idealny sposób na napisanie tego, ale jest to możliwość, którą ktoś może wybrać, z dowolnego powodu.
user625488
0

Myślę, że po prostu definiują nienazwany poziom zakresu.

Peter Mortensen
źródło
0

Przenieś zakres, kopia nie będzie widoczna poza nim, więc możesz później zadeklarować inną zmienną o tej samej nazwie. I może zostać zebrany przez moduł odśmiecania zaraz po wyjściu z tego zakresu. W tym przypadku kopia służy jako zmienna tymczasowa, więc jest to dobry przykład.

Pavel Feldman
źródło