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?

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.


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.


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.


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.


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 ++.


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
  }
}

1

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


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.


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


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.