Ukryte funkcje Java


295

Po przeczytaniu ukrytych funkcji języka C # zastanawiałem się, jakie są niektóre z ukrytych funkcji Java?


17
Pamiętaj, że korzystanie z tych ukrytych funkcji nie zawsze jest dobrym pomysłem; często są zaskakujące i mylące dla osób czytających Twój kod.
Kevin Bourrillion

1
Ty (/ ktoś) najprawdopodobniej starannie podsumuj odpowiedzi w treści pytania, np. W języku C #.
ripper234,

Odpowiedzi:


432

Inicjacja Double Brace zaskoczyła mnie kilka miesięcy temu, kiedy ją odkryłem, nigdy wcześniej o niej nie słyszałem.

ThreadLocals zazwyczaj nie są tak powszechnie znane jako sposób przechowywania stanu poszczególnych wątków.

Ponieważ JDK 1.5 Java ma wyjątkowo dobrze zaimplementowane i niezawodne narzędzia do współbieżności poza blokadami, znajdują się one w java.util.concurrent, a szczególnie interesującym przykładem jest java.util.concurrent.atomic podpakiet zawierający bezpieczne dla wątków operacje podstawowe, które implementują porównanie -i-swap operacji i może mapować do rzeczywistych obsługiwanych sprzętowo wersji tych operacji.


40
Inicjacja podwójnego nawiasu klamrowego ... dziwne ... Uważam jednak, że zbyt szeroko przyjmuję ten konkretny idiom, ponieważ w rzeczywistości tworzy on anonimową podklasę obiektu, co może powodować mylące problemy z równaniem / hashodem. java.util.concurrent to naprawdę świetny pakiet.
MB.

6
Mam nauczył Java, i to jest raz pierwszy natknąłem tej składni ... co dowodzi, że nigdy nie przestają się uczyć = 8-)
Yuval

49
Zauważ, że jeśli zachowasz odwołanie do kolekcji zainicjowanej tym idiomem „podwójnego nawiasu klamrowego” (lub jeśli nazwiemy ją prawdziwą nazwą - klasa anonimowa z blokiem inicjującym), domyślnie przechowujesz odwołanie do zewnętrznego obiektu, który może powodować nieprzyjemną pamięć przecieki Radziłbym całkowicie tego unikać.
ddimitrov

51
„Inicjacja podwójnego nawiasu klamrowego” jest bardzo eufemistyczną nazwą tworzenia anonimowej klasy wewnętrznej, przypominania o tym, co naprawdę się dzieje i nadawania temu brzmienia, jakby klasy wewnętrzne miały być używane w ten sposób. Ten wzór wolałbym pozostać ukryty.
erickson,

11
Prawie nie jest to tak naprawdę blok statyczny, ale „blok inicjalizujący”, który jest inny, ponieważ jest wykonywany w innym czasie (więcej szczegółów znajduje się w linku, który zamieszczam w odpowiedzi)
Boris Terzic,

279

Łączna zmienność parametru typu:

public class Baz<T extends Foo & Bar> {}

Na przykład, jeśli chcesz wziąć parametr, który jest zarówno Porównywalny, jak i Kolekcja:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

Ta wymyślona metoda zwraca wartość true, jeśli dwie podane kolekcje są równe lub jeśli jedna z nich zawiera dany element, w przeciwnym razie fałsz. Należy zauważyć, że można wywoływać metody zarówno Porównywalne, jak i Kolekcji na argumentach b1 i b2.


Moim ulubionym zastosowaniem jest to, gdy potrzebujesz metody, która akceptuje Dopuszczalne Ciągi.
Neil Coffey,

5
Czy możliwe jest użycie „LUB” zamiast &?
mainstringargs

9
@Grasper: Nie, OR (rozłączny związek) nie jest podany w tym kontekście. Ale zamiast tego możesz użyć rozłącznego typu danych unii, takiego jak <A, B>. Ten typ jest podwójny typu Pair <A, B>. Spójrz na bibliotekę Functional Java lub biblioteki podstawowe Scala na przykład takiego typu danych.
Apocalisp

5
Powinieneś powiedzieć, że MUSISZ rozszerzyć tylko jedną klasę i kilka interfejsów -> klasa publiczna Baz <T rozszerza Clazz & Interface1 & InterfaceI ... a nie klasa Baz <T rozszerza Clazz1 & ClazzI>
JohnJohnGa 17.10

220

Byłem zaskoczony inicjatorami instancji innego dnia. Usunąłem niektóre złożone metody i ostatecznie utworzyłem wiele inicjatorów instancji:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

Wykonanie mainmetody wyświetli:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

Sądzę, że byłyby przydatne, gdybyś miał wiele konstruktorów i potrzebował wspólnego kodu

Zapewniają również cukier składniowy do inicjowania twoich zajęć:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

38
Zaletą tego nad jawną metodą, którą należy wywołać, jest to, że jeśli ktoś doda konstruktor później, nie musi pamiętać o wywołaniu init (); zrobi to automatycznie. Może to zapobiec błędom przyszłych programistów.
Mr. Shiny and New 安 宇

40
Ponadto, w przeciwieństwie do metody init (), może inicjować końcowe pola.
Darron

2
Co się stanie, jeśli rozszerzysz klasę i stworzysz różne dzieci? Czy nadal będzie zachowywać się w ten sam sposób?
Kezzer

12
Ludzie często odmawiają certyfikacji (np. Stackoverflow.com/questions/281100/281127#281127 ), a zwłaszcza kwestionują ich zalety techniczne. Ale gdyby więcej programistów tutaj studiowało dla SCJP, tak wielu nie uznałoby tego za „ukrytą funkcję”. ;-)
Jonik

12
Założę się, że nawet książka „java in 24 hours” ma tę „oczywistą cechę”. czytaj więcej facetów
:)

201

JDK 1.6_07 + zawiera aplikację o nazwie VisualVM (bin / jvisualvm.exe), która jest przyjemnym GUI na wielu narzędziach. Wydaje się bardziej wszechstronny niż JConsole.


I ma wtyczkę (jest to gra Netbeans), która pozwala jej używać wtyczek Jconsole. Całkiem miło.
Thorbjørn Ravn Andersen

VisualVM jest najlepszą rzeczą od krojonego chleba, naprawdę! Szkoda, że ​​nie ma wszystkich funkcji, gdy działa przeciwko JDK 1.5
sandos

Uważam, że VisualVM jest powolny lub w niektórych przypadkach bezużyteczny. Komercyjny YourKit nie ma tego problemu, ale niestety nie jest bezpłatny.
Roalt

Nowsze wersje Visual VM, od JDK 1.6.0_22 i późniejszych, są znacznie ulepszone. Założę się, że JDK1.7 ma jeszcze lepszą wersję.
djangofan


156

Dla większości osób, z którymi przeprowadzam wywiady dla stanowisk programistów Java, bloki oznaczone jako zaskakujące. Oto przykład:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

Kto powiedział, że gotow java to tylko słowo kluczowe? :)


2
Cóż, wolałbym mieć opcję zrobienia tego na kilka sposobów. Na przykład widziałem ludzi używających System.exit (1); w kodzie Servlet i EJB, ale to nie znaczy, że powinniśmy usunąć System.exit (); z JDK, prawda?
Georgy Bolyuba,

31
W niektórych okolicznościach w obrębie zagnieżdżonej konstrukcji pętli przydatne może być przejście do następnej iteracji zewnętrznej pętli. Byłoby to rozsądne wykorzystanie tej funkcji.
alasdairg

75
Tym, co jest szczególnie nieznane wielu programistom (i prawdopodobnie równie dobrze), jest to, że można właściwie opisać i zerwać KAŻDY stary blok. Nie musi to być pętla - możesz po prostu zdefiniować dowolny blok, nadać mu etykietę i użyć z nim przerwy.
Neil Coffey,

27
To wcale nie jest goto, może tylko wrócić do poprzedniej iteracji (tzn .: nie można przeskoczyć do przodu). Jest to ten sam mechanizm, który występuje, gdy iteracja zwraca wartość false. Mówienie goto java jest jak powiedzenie, że każdy język, którego kompilator wytwarza instrukcję JUMP, ma instrukcję goto.
Zombie

4
Więc przeprowadzasz wywiad oparty na ciekawostkach związanych z Javą, a nie na umiejętności rozwiązywania problemów i przemyślania projektów. Upewnię się, że nigdy nie przeprowadzę wywiadu z twoją firmą. :)
Javid Jamae

144

A co z typami zwrotów kowariantnych które obowiązywały od JDK 1.5? Jest dość słabo nagłośniony, ponieważ jest nieprzyzwoitym dodatkiem, ale jak rozumiem, jest absolutnie niezbędny do działania leków generycznych.

Zasadniczo kompilator pozwala teraz podklasie zawęzić typ zwracany przez przesłoniętą metodę, aby była podklasą typu zwracanego przez oryginalną metodę. Jest to dozwolone:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

Możesz wywołać valuesmetodę podklasy i otrzymać posortowany wątek bezpieczny Setod Strings bez konieczności rzutowania do ConcurrentSkipListSet.


Czy możesz podać przykładowe użycie?
Allain Lalonde

24
Często tego używam. clone () jest świetnym przykładem. Ma zwracać Object, co oznacza, że ​​musisz powiedzieć np. (List) list.clone (). Jeśli jednak zadeklarujesz jako List clone () {...}, rzutowanie jest niepotrzebne.
Jason Cohen,

142

Przeniesienie kontroli w bloku ostatecznie odrzuca każdy wyjątek. Poniższy kod nie zgłasza wyjątku RuntimeException - został utracony.

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

From http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


7
To paskudne, ale jest też logiczną konsekwencją tego, jak w końcu działa. Kontrola przepływu try / catch / wreszcie wykonuje to, co jest zamierzone, ale tylko w określonych granicach. Podobnie musisz uważać, aby nie spowodować wyjątku w bloku catch / wreszcie, bo inaczej wyrzucisz oryginalny wyjątek. A jeśli wykonasz System.exit () wewnątrz bloku try, blok w końcu nie zostanie wywołany. Jeśli przerwiesz normalny przepływ, przerwiesz normalny przepływ ...
Neil Coffey,

Nie używaj w końcu {return; }, ale w końcu {kod bez powrotu}. Jest to logiczne, ponieważ w końcu ma być również wykonywane, gdy wystąpiły wyjątki, a jedynym możliwym znaczeniem powrotu jako procedury obsługi wyjątku musi być zignorowanie wyjątku i - rzeczywiście - powrót.
extraneon

21
Wydaje się, że to raczej „gotcha” niż ukryta funkcja, choć istnieją sposoby, w jakie można by jej użyć jako jednej, użycie tej metody nie byłoby dobrym pomysłem.
davenpcj

Eclipse wysyła ostrzeżenie, jeśli to zrobisz. Jestem z Eclipse. Jeśli chcesz złapać wyjątek ... to złap wyjątek.
helios

To właśnie płacisz za brudny kod, który zwraca się od środka metody. Ale wciąż dobry przykład.
Rostislav Matl

141

Nie widziałem, żeby ktoś wspominał wystąpienie implementacji w taki sposób, że sprawdzanie wartości null nie jest konieczne.

Zamiast:

if( null != aObject && aObject instanceof String )
{
    ...
}

po prostu użyj:

if( aObject instanceof String )
{
    ...
}

9
Szkoda, że ​​jest to tak mało znana funkcja. Widziałem dużo kodu podobnego do pierwszego bloku kodu.
Peter Dolberg

4
Jest tak, ponieważ Java ma specjalny (ukryty) typ zerowy, którego nie widzisz ani do którego nie możesz się odwoływać.
Nick Hristov

Co gorsze, sprawdzanie wartości null przed freeing lub deleteing w C / C ++. Taka podstawowa koncepcja.
Thomas Eding

134

Zezwalanie na metody i konstruktorów w wyliczeniach zaskoczyło mnie. Na przykład:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

Możesz nawet mieć „stałe określone ciało klasy”, które pozwala określonej wartości wyliczeniowej zastąpić metody.

Więcej dokumentacji tutaj .


20
Naprawdę niesamowita funkcja - sprawia, że ​​wylicza OO i rozwiązuje wiele problemów z inicjalizacją w bardzo czysty sposób.
Bill K,

5
Enum jako singleton? Wylicz tylko jedną wartość?
Georgy Bolyuba,

6
Georgy: Singleton jest jedną instancją obiektu, a nie obiektem o jednej wartości.
dshaw,

20
@Georgy: patrz także pozycja 3 w Effective Java Joshua Blocha (wydanie 2); „Chociaż takie podejście nie zostało jeszcze powszechnie przyjęte, jednoelementowy typ wyliczenia jest najlepszym sposobem na wdrożenie singletonu”.
Jonik

3
Drobny nitpick: mAgepowinien być ostateczny. Rzadko jest powód, dla którego nieumiejętności są w wyliczeniach.
Joachim Sauer

121

Parametry typu dla metod ogólnych można jawnie określić w następujący sposób:

Collections.<String,Integer>emptyMap()

10
I na Boga, czy to brzydkie i zagmatwane. I nie ma znaczenia dla bezpieczeństwa typu.
Chris Broadfoot

8
Uwielbiam to. Sprawia, że ​​twój kod jest bardziej wyraźny i jako taki bardziej zrozumiały dla biednego drania, który będzie musiał go utrzymać za rok lub dwa.
extraneon

6
Jest to w rzeczywistości bardzo przydatne w sytuacjach, w których zadeklarowałeś ogólną metodę statyczną, taką jak public static <T> T foo(T t). Możesz wtedy dzwonić doClass.<Type>foo(t);
Finbarr

Z jakiegoś powodu nie działa to z metodami importowanymi statycznie. Zastanawiam się, dlaczego.
oksayt,

Jest to szczególnie przydatne, gdy używasz trójskładnikowych ifs ze zwrotem. Na przykład return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList(). Przydaje się również w przypadku niektórych wywołań metod, w których prosta kolekcja.emptyMap () dawałaby błąd kompilacji.
Andreas Holstenson

112

Możesz użyć wyliczeń, aby zaimplementować interfejs.

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

EDYCJA: Lata później ....

Korzystam z tej funkcji tutaj

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java

Korzystając z interfejsu, programiści mogą definiować własne strategie. Za pomocą enumśrodków mogę zdefiniować kolekcję (pięciu) wbudowanych.


27
To szaleństwo. (+1)
Głowonóg

12
@Arian, to nie jest szaleństwo. TO. JEST. JAVAAAAAAAAA!
slezica

1
WHAAAAAT nie, jestem z Adrianem. To nie jest Java. To szaleństwo. Chętnie tego użyję.
slezica

104

Począwszy od Java 1.5, Java ma teraz znacznie bardziej przejrzystą składnię do pisania funkcji o różnym arity. Zamiast więc przekazywać tablicę, teraz możesz wykonać następujące czynności

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

słupki są automatycznie konwertowane na tablicę określonego typu. Nie jest to wielka wygrana, ale mimo to wygrana.


23
Ważną rzeczą jest to, że wywołując metodę, możesz napisać: foo („pierwszy”, „drugi”, „trzeci”)
Steve Armstrong

9
więc stary świat cześć może zostać przepisany; public static void main (String ... args) {System.out.println („Hello World!”); }
Karussell

@Karussell Może, ale wydaje się, że argumenty są nieistotne: p
Kelly Elton

93

Moje ulubione: zrzuć wszystkie ślady stosu nici na standardowe wyjście.

windows: CTRL- Breakw twoim oknie Java CdD / konsoli

unix: kill -3 PID


15
Również ctrl- \ w Uniksie. Lub użyj jstack z JDK.
Tom Hawtin - tackline

9
Dzięki, właśnie nauczyłeś mnie, że moja klawiatura ma Breakklawisz.
Amy B,

2
W systemie Windows CTRL-BREAK działa tylko wtedy, gdy proces działa w bieżącym oknie konsoli. Zamiast tego możesz użyć JAVA_HOME / bin / jstack.exe. Wystarczy podać identyfikator procesu systemu Windows.
Javid Jamae

Myślałem, że to zabić -SIGQUIT
Nick Hristov

@Nick, tak SIGQUIT jest zwykle sygnałem nr 3.
Chris Mazzola

89

Kilka osób napisało o inicjatorach instancji, oto dobre zastosowanie:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

To szybki sposób na inicjalizację map, jeśli robisz coś szybko i prosto.

Lub używając go do stworzenia prototypu szybkiej ramy wychylnej:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

Oczywiście można go nadużywać:

    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

W jakiś sposób jest to trochę tak, jakby słowo kluczowe „z” (właściwie funkcjonalność) zostało dodane do Javy. Może być bardzo przydatny, ostatnio chrząknąłem, ponieważ inicjowanie tablic nie było dostępne dla kolekcji. Dzięki!
PhiLho,

15
Istnieje jednak jeden efekt uboczny korzystania z tego. Tworzone są anonimowe obiekty, co nie zawsze jest w porządku.
amit

17
Chociaż po dokładniejszym przyjrzeniu się temu muszę przyznać, że dziwnie pociąga mnie to naturalne zagnieżdżanie, nawet wersja „nadużywana”.
Bill K

4
Tak - całkiem podoba mi się ta „nadużywana” wersja, myślę, że to naprawdę bardzo jasne i czytelne, ale może to tylko ja.
zabezpieczył

3
Absolutnie się zgadzam, że hierarchia kodu odzwierciedlająca hierarchię GUI jest ogromnym ulepszeniem w stosunku do sekwencji wywołań metod.
opsb

88

Dynamiczne proxy (dodane w 1.3) pozwalają zdefiniować nowy typ w czasie wykonywania, który jest zgodny z interfejsem. Przydaje się zaskakująco wiele razy.


10
Dynamiczne proxy to świetny powód, aby wybrać interfejs Foo i używać go wszędzie, z domyślną klasą „FooImpl”. Z początku może się to wydawać brzydkie („Dlaczego po prostu nie mieć klasy Foo?”), Ale przydatne są przyszłe możliwości elastyczności i próbnego testowania jednostek. Chociaż istnieją sposoby na wykonanie tego również w przypadku interfejsów innych niż standardowe, zazwyczaj wymagają one dodatkowych rzeczy, takich jak cblib.
Darien

82

ostateczna inicjalizacja może zostać odroczona.

Zapewnia to, że nawet przy złożonym przepływie logiki zwracane są zawsze wartości. Zbyt łatwo przeoczyć skrzynkę i przez przypadek zwrócić wartość zerową. Nie uniemożliwia powrotu wartości null, po prostu oczywiste, że jest to celowe:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

To zaskakujące. Czy można rzetelnie powiedzieć: „Wartość zmiennej końcowej można ustawić raz”, bez względu na to, gdzie występuje zestaw?
David Koelle

29
Tak, ale mocniej: „Wartość zmiennej końcowej należy ustawić raz”
Allain Lalonde

6
+1 Zgadzam się, jest to kolejne cenne narzędzie do wykrywania błędów w czasie kompilacji, z którego programiści wydają się być nieśmiali z jakiegoś powodu. Zauważ, że ponieważ od wersji Java 5 „końcowy” ma również wpływ na bezpieczeństwo wątków, możliwość ustawienia końcowej zmiennej podczas konstruktora jest nieoceniona.
Neil Coffey,

4
Chociaż dla tej konkretnej metody użyłbym tylko wielu zwrotów. W rzeczywistości, w większości przypadków, gdy ma to zastosowanie, prawdopodobnie przefakturowałbym go na osobną metodę i użyłbym wielu zwrotów.
ripper234

Uwielbiam to! Zawsze usuwałem ostatnie słowo kluczowe, ponieważ myślałem, że się nie powiedzie. dzięki!
KARASZI István

62

Myślę, że inną „przeoczoną” cechą Java jest sama JVM. Jest to prawdopodobnie najlepsza dostępna maszyna wirtualna. Obsługuje wiele interesujących i przydatnych języków (Jython, JRuby, Scala, Groovy). Wszystkie te języki mogą łatwo i bezproblemowo współpracować.

Jeśli projektujesz nowy język (jak w przypadku Scala), natychmiast dostępne są wszystkie istniejące biblioteki, a zatem Twój język jest „użyteczny” od samego początku.

Wszystkie te języki korzystają z optymalizacji HotSpot. Maszyna wirtualna jest bardzo dobrze monitorowana i debugowana.


18
Nie. W rzeczywistości nie jest to bardzo dobra maszyna wirtualna. Został zaprojektowany wyłącznie do obsługi JAVA. Typowe dynamiczne i funkcjonalne języki nie działają z nim dobrze. Jeśli chcesz używać maszyny wirtualnej, powinieneś użyć .NET / Mono. Został zaprojektowany do pracy z
KAŻDYM

14
W rzeczywistości JVM jest przeznaczony wyłącznie do uruchamiania Java Bytecodes. Możesz skompilować większość współczesnych języków do kodu Java Bytecode. Jedyne, czego brakuje Java Bytecode, to dynamiczna obsługa języka, wskaźniki i obsługa rekurencji ogona.
mcjabberz

12
@ Hades32: faktycznie .NET VM jest bardzo podobny do JVM. Dopiero niedawno uzyskał wsparcie dla języków dynamicznych (wraz z DLR), a Java 7 wkrótce też otrzyma tę obsługę. A klasyczny „KAŻDY język” .NET (C #, Visual Basic.NET, ...) ma dokładnie taki sam zestaw funkcji.
Joachim Sauer

13
JVM nie obsługuje generycznych, podczas gdy .NET VM. JVM nigdzie nie jest najlepszy.
Blindy,

3
Nie pomijając skarg na określone funkcje językowe, które nie są bezpośrednio obsługiwane przez JVM ... ale wydaje mi się, że stabilność, spójność między platformami i dobra wydajność to znacznie więcej niż powody, dla których JVM otrzymuje dodatkowe punkty. Od wielu lat pracuję z Javą po stronie serwera na wielu platformach (w tym AS / 400) i prawie całkowicie o tym zapomniałem - błędy są prawie zawsze w kodzie, który mogę naprawić, i to po prostu się nie zawiesza.
Rob Whelan,

58

Możesz zdefiniować anonimową podklasę i bezpośrednio wywołać na niej metodę, nawet jeśli nie implementuje ona żadnych interfejsów.

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

@Vuntic - Pozwala zdefiniować prostą klasę w kontekście, który jest potrzebny.
ChaosPandion,

1
@Chaos, ale dlaczego? Masz rzeczywisty przykład, w którym jest przydatny?
Thorbjørn Ravn Andersen

10
@Wouter - W takim przypadku metoda wywołana na obiekcie anonimowym ( start()) nie jest tak naprawdę zdefiniowana w podklasie ...
Axel

W rzeczywistości jest to bardzo przydatna funkcja, jeśli rozszerzysz klasę podstawową, która wymaga pewnych ustawień, wywoła metodę, którą piszesz, a następnie usuwa. Rozpocznij, wywołując metodę w klasie podstawowej (której prawdopodobnie nie nadałbym tej samej nazwy). Jest to przykład zastosowanie (nie definicja) tutaj
AmigoNico

56

AsList metoda java.util.Arraysumożliwia połączenie miłe z varargs, metod generycznych i autoboxing:

List<Integer> ints = Arrays.asList(1,2,3);

15
chcesz zawinąć zwróconą listę za pomocą konstruktora List, w przeciwnym razie ints będzie miał stały rozmiar (ponieważ jest on wspierany przez tablicę)
KitsuneYMG

2
Arrays.asListMa niezwykłą cechę, że można set()elementy, ale nie add()bądź remove(). Więc zwykle zawijam go w a new ArrayList(...)lub a Collections.unmodifiableList(...), w zależności od tego, czy chcę modyfikować listę, czy nie.
Christian Semrau,

53

Użycie tego słowa kluczowego do uzyskania dostępu do pól / metod zawierających klasę z klasy wewnętrznej. W poniższym, raczej wymyślonym przykładzie, chcemy użyć pola sortAscending klasy kontenera od anonimowej klasy wewnętrznej. Używanie ContainerClass.this.sortAscending zamiast this.sortAscending załatwia sprawę.

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
Jest to konieczne tylko wtedy, gdy nazwa została zaciemniona (w twoim przypadku z nazwą parametru metody). Jeśli nazwałbyś ten argument czymś innym, wówczas możesz bezpośrednio uzyskać dostęp do zmiennej członka sortAscending klasy Container bez użycia „this”.
sk.

7
Nadal przydatne jest odwołanie do otaczającej klasy, np. jeśli musisz przekazać to jakiejś metodzie lub konstruktorowi.
PhiLho

Często używany w rozwoju układu Androida, aby uzyskać kontekst od, powiedzmy, słuchacza przycisku, z MyActivity.this.
espinchi

52

Nie jest to właściwie funkcja, ale zabawna sztuczka, którą odkryłem niedawno na jakiejś stronie internetowej:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

jest poprawnym programem Java (chociaż generuje ostrzeżenie). Jeśli nie rozumiesz dlaczego, zobacz odpowiedź Gregory'ego! ;-) Podświetlanie składni również daje wskazówkę!


15
schludnie, etykieta z komentarzem :)
Thorbjørn Ravn Andersen

46

Nie są to do końca „ukryte funkcje” i nie są bardzo przydatne, ale w niektórych przypadkach mogą być niezwykle interesujące:
Klasa sun.misc.Unsafe - pozwoli ci wdrożyć bezpośrednie zarządzanie pamięcią w Javie (możesz nawet napisać samomodyfikujący się kod Java za pomocą jeśli dużo próbujesz):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
to jest słońce. * API, które tak naprawdę nie jest częścią języka Java jako takiego
DW.

W Unsafe istnieje wiele innych ciekawych metod, takich jak tworzenie obiektu bez wywoływania konstruktora, metody stylu malloc / realloc / free.
Peter Lawrey

Uwielbiam zwłaszcza prymitywne funkcje pobierające i ustawiające w lokalizacjach pamięci, takie jak putDouble (długi adres, podwójne d).
Daniel

42

Podczas pracy w Swing lubię ukryte Ctrl- Shift-F1 funkcja .

Zrzuca drzewo komponentów bieżącego okna.
(Zakładając, że nie związałeś tego naciśnięcia klawisza z czymś innym).


1
Najprawdopodobniej twój menedżer okien ma coś związanego z tym kluczem. Gnome się z tym nie wiąże, więc zakładam, że używasz KDE, które wiąże go z „przełączeniem na pulpit 13”. Możesz to zmienić, przechodząc do Panelu sterowania, Skrótów regionalnych, Skrótów klawiaturowych i usuwając mapowanie Shift-Ctrl-F1
Devon_C_Miller

40

Każdy plik klasy zaczyna się od wartości szesnastkowej 0xCAFEBABE celu zidentyfikowania go jako prawidłowego kodu bajtowego JVM.

( Wyjaśnienie )


38

Głosuję na java.util.concurrent z jego równoległymi kolekcjami i elastycznymi programami wykonawczymi, umożliwiającymi między innymi pule wątków, zaplanowane zadania i skoordynowane zadania. DelayQueue jest moim osobistym ulubieńcem, w którym elementy są udostępniane po określonym czasie.

java.util.Timer i TimerTask można bezpiecznie zatrzymać.

Nie do końca ukryte, ale w innym pakiecie niż inne klasy związane z datą i godziną. java.util.concurrent.TimeUnit jest przydatny podczas konwersji między nanosekundami, mikrosekundami, milisekundami i sekundami.

Czyta o wiele lepiej niż zwykle someValue * 1000 lub someValue / 1000.


Ostatnio odkryte CountDownLatchi CyclicBarrier- bardzo przydatne!
Raphael

37

Słowo kluczowe aser na poziomie języka .


19
Problem z asersem polega na tym, że należy go włączyć w czasie wykonywania.
extraneon

10
Ale jeśli jest wyłączone, to tak, jakby go nie było. Możesz dodać tyle kodów, ile chcesz w swoim kodzie i nie będziesz mieć żadnych ograniczeń wydajności, jeśli zostaną wyłączone.
Ravi Wallau,

5
Uważam, że to dobra rzecz w twierdzeniu: można ją wyłączyć bez kary.
andref

problem polega na tym, że jeśli przypadkowo zaimplementowałeś efekt uboczny w asercie, musisz włączyć asercję dla swojego programu do działania ...
Chii,

Aby wykryć, czy aserty są włączone, możesz użyć {boolean assertsOn = false; assert assertsOn = true; if (assertsOn) {/ * weryfikacja złożona * /}}. Umożliwia to także rejestrowanie lub zgłaszanie wyjątku, jeśli stan potwierdzenia nie jest oczekiwany.
fernacolo

37

W rzeczywistości nie jest częścią języka Java, ale dezasembler javap dostarczany z JDK firmy Sun nie jest powszechnie znany ani używany.


36

Dodanie konstrukcji pętli dla każdego w 1.5. <3 to.

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

I może być używany w instancjach zagnieżdżonych:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

Konstrukcja for-each ma również zastosowanie do tablic, w których ukrywa zmienną indeksu zamiast iteratora. Poniższa metoda zwraca sumę wartości w tablicy int:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

Link do dokumentacji Sun


30
Myślę, że używanie itutaj jest bardzo mylące, ponieważ większość ludzi oczekuje, że będę indeksem, a nie elementem tablicy.
cdmckay

Więc ... int sum (int [] array) {int result = 0; for (int element: array) {result + = element; } zwróć wynik; }
Drew

28
Jedyną rzeczą, która doprowadza mnie do szału jest to, że wydaje się, że naprawdę bardzo łatwo byłoby utworzyć słowo kluczowe, aby uzyskać dostęp do wartości liczby pętli, ale nie możesz. Jeśli chcę zapętlić dwie tablice i wprowadzić zmiany w drugiej w oparciu o wartości w pierwszej, jestem zmuszony użyć starej składni, ponieważ nie mam przesunięcia w drugiej tablicy.
Jherico

6
Szkoda, że ​​nie działa również z wyliczeniami, takimi jak te używane w JNDI. Wrócił do iteratorów.
extraneon

3
@extraneon: spójrz na Collections.list (Enumeration <T> e). To powinno pomóc w iteracji wyliczeń w pętli foreach.
Werner Lehmann

34

osobiście odkryłem java.lang.Voidbardzo późno - poprawia czytelność kodu w połączeniu z generycznymi, npCallable<Void>


2
nie do końca. w pewnym momencie musisz być konkretny: Executors.newSingleThreadExecutor (). zgłoś (nowa wywoływalna <Void> () {..}) - nie możesz utworzyć nowej wywoływalnej <?> (), musisz określić typ jawny - dlatego jest alternatywą dla wywoływalnego <Object>.
Rahel Lüthy,

4
Pustka jest bardziej specyficzna niż Obiekt, ponieważ Pustka może być tylko pusta, Obiekt może być dowolna.
Peter Lawrey,
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.