Versteckte Funktionen von Java


295

Nachdem ich die versteckten Funktionen von C # gelesen hatte, fragte ich mich: Was sind einige der versteckten Funktionen von Java?


17
Beachten Sie, dass es nicht immer eine gute Idee ist, diese versteckten Funktionen zu verwenden. Oft sind sie überraschend und verwirrend für andere, die Ihren Code lesen.
Kevin Bourrillion

1
Sie (/ jemand) sollten wahrscheinlich die Antworten im Fragenkörper wie die C # -Frage ordentlich zusammenfassen.
Ripper234

Antworten:


432

Die Doppelklammer-Initialisierung hat mich vor einigen Monaten überrascht, als ich sie zum ersten Mal entdeckte und noch nie davon gehört habe.

ThreadLocals sind normalerweise nicht so weit verbreitet, um den Status pro Thread zu speichern.

Da in JDK 1.5 Java äußerst gute und robuste Parallelitätstools vorhanden sind, die über Sperren hinausgehen, befinden sie sich in java.util.concurrent. Ein besonders interessantes Beispiel ist das Unterpaket java.util.concurrent.atomic , das thread-sichere Grundelemente enthält, die den Vergleich implementieren -und-Swap- Vorgang und kann tatsächlichen nativen hardwareunterstützten Versionen dieser Vorgänge zugeordnet werden.


40
Double-Brace-Initialisierung ... seltsam ... Ich würde mich jedoch davor hüten, diese bestimmte Redewendung zu weit zu übernehmen, da dadurch tatsächlich eine anonyme Unterklasse des Objekts erstellt wird, was zu verwirrenden Gleichheits- / Hashcode-Problemen führen kann. java.util.concurrent ist ein wirklich großartiges Paket.
MB.

6
Ich habe Java unterrichtet , und dies ist das allererste Mal, dass ich auf diese Syntax gestoßen bin ... was zeigt, dass Sie nie aufhören zu lernen = 8-)
Yuval

49
Beachten Sie, dass Sie implizit einen Verweis auf das äußere Objekt halten, wenn Sie einen Verweis auf eine Sammlung beibehalten, die mit dieser "doppelten Klammer" initialisiert wurde (oder wenn wir ihn beim richtigen Namen nennen - anonyme Klasse mit Initialisierungsblock), was zu unangenehmem Speicher führen kann Leckagen. Ich würde empfehlen, es ganz zu vermeiden.
ddimitrov

51
"Double-Brace-Initialisierung" ist ein sehr euphemistischer Name für die Erstellung einer anonymen inneren Klasse, die beschönigt, was wirklich passiert, und den Eindruck erweckt, dass innere Klassen auf diese Weise verwendet werden sollen. Dies ist ein Muster, das ich lieber versteckt bleiben möchte.
Erickson

11
Fast ist es nicht wirklich ein statischer Block, sondern ein "Initialisierungsblock", der anders ist, da er zu einer anderen Zeit ausgeführt wird (siehe den Link, den ich in die Antwort eingefügt habe, für weitere Details)
Boris Terzic

279

Gemeinsame Vereinigung in der Varianz der Typparameter:

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

Wenn Sie beispielsweise einen Parameter verwenden möchten, der sowohl vergleichbar als auch eine Sammlung ist:

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

Diese erfundene Methode gibt true zurück, wenn die beiden angegebenen Sammlungen gleich sind oder wenn eine von ihnen das angegebene Element enthält, andernfalls false. Beachten Sie, dass Sie für die Argumente b1 und b2 Methoden von Comparable und Collection aufrufen können.


Meine bevorzugte Verwendung hierfür ist, wenn Sie eine Methode benötigen, die eine anhängbare Zeichenfolge akzeptiert.
Neil Coffey

5
Ist es möglich, dort ein "ODER" anstelle des & zu haben?
Mainstringargs

9
@Grasper: Nein, OR (disjunkte Vereinigung) wird in diesem Kontext nicht bereitgestellt. Sie können jedoch stattdessen einen disjunkten Vereinigungsdatentyp wie Entweder <A, B> verwenden. Dieser Typ ist das Dual eines Pair <A, B> -Typs. Ein Beispiel für einen solchen Datentyp finden Sie in der Functional Java-Bibliothek oder in den Scala-Kernbibliotheken.
Apocalisp

5
Sie sollten sagen, dass Sie nur eine Klasse und mehrere Schnittstellen erweitern MÜSSEN -> öffentliche Klasse Baz <T erweitert Clazz & Interface1 & InterfaceI ... und nicht Klasse Baz <T erweitert Clazz1 & ClazzI>
JohnJohnGa

220

Ich war neulich von Instanzinitialisierern überrascht. Ich habe einige Code-Folded-Methoden gelöscht und am Ende mehrere Instanzinitialisierer erstellt:

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

Wenn Sie die mainMethode ausführen , wird Folgendes angezeigt:

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

Ich denke, diese wären nützlich, wenn Sie mehrere Konstruktoren hätten und gemeinsamen Code benötigen würden

Sie bieten auch syntaktischen Zucker zum Initialisieren Ihrer Klassen:

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
Dies hat gegenüber einer expliziten Methode, die aufgerufen werden muss, den Vorteil, dass jemand, der später einen Konstruktor hinzufügt, nicht daran denken muss, init () aufzurufen. das wird automatisch gemacht. Dies kann Fehler durch zukünftige Programmierer verhindern.
Mr. Shiny und New

40
Im Gegensatz zu einer init () -Methode können auch endgültige Felder initialisiert werden.
Darron

2
Was ist, wenn Sie die Klasse erweitern und verschiedene Kinder instanziieren? Wird es sich immer noch genauso verhalten?
Kezzer

12
Menschen dis zertifizieren häufig (z. B. stackoverflow.com/questions/281100/281127#281127 ) und stellen insbesondere ihre technischen Vorzüge in Frage. Aber wenn mehr Programmierer hier für ihr SCJP studiert hätten, würde dies von so vielen nicht als "verstecktes Merkmal" angesehen werden. ;-)
Jonik

12
Ich wette sogar, dass "Java in 24 Stunden" dieses "offensichtliche Merkmal" hat. Lesen Sie mehr Jungs
Özgür

201

JDK 1.6_07 + enthält eine App namens VisualVM (bin / jvisualvm.exe), die eine nette GUI über vielen Tools ist. Es scheint umfassender als JConsole.


Und es hat ein Plugin (es ist ein Netbeans-Ding), mit dem es Jconsole-Plugins verwenden kann. Recht nett.
Thorbjørn Ravn Andersen

VisualVM ist wirklich das Beste seit geschnittenem Brot! Schade, dass es nicht alle Funktionen hat, wenn es gegen JDK 1.5 läuft
Sandos

Ich finde VisualVM unter bestimmten Umständen langsam oder unbrauchbar. Das kommerzielle YourKit hat dieses Problem nicht, ist aber leider nicht kostenlos.
Roalt

Die neueren Versionen von Visual VM ab JDK 1.6.0_22 und höher wurden erheblich verbessert. Ich würde wetten, dass JDK1.7 eine noch bessere Version davon hat.
Djangofan


156

Für die meisten Leute, die ich für Java-Entwicklerpositionen interviewe, sind mit Blöcken gekennzeichnete Blöcke sehr überraschend. Hier ist ein Beispiel:

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

Wer hat gotoin Java gesagt, ist nur ein Schlüsselwort? :) :)


2
Nun, ich würde es vorziehen, eine Option zu haben, um es auf verschiedene Arten zu tun. Ich habe zum Beispiel Leute gesehen, die System.exit (1) verwendet haben. in Servlet- und EJB-Code, aber das bedeutet nicht, dass wir System.exit () entfernen sollten; vom JDK, richtig?
Georgy Bolyuba

31
Unter bestimmten Umständen kann es innerhalb eines verschachtelten Schleifenkonstrukts nützlich sein, mit der nächsten Iteration einer äußeren Schleife fortzufahren. Dies wäre eine vernünftige Verwendung dieser Funktion.
Alasdairg

75
Was vielen Programmierern (und wahrscheinlich auch) nicht bekannt ist, ist, dass Sie tatsächlich JEDEN alten Block beschriften und aus ihm ausbrechen können. Es muss keine Schleife sein - Sie können einfach einen beliebigen Block definieren, ihm eine Bezeichnung geben und break damit verwenden.
Neil Coffey

27
Es ist überhaupt kein Goto, es kann nur zu einer vorherigen Iteration zurückkehren (dh Sie können nicht vorwärts springen). Dies ist derselbe Mechanismus, der auftritt, wenn eine Iteration false zurückgibt. Zu sagen, dass Java goto ist, ist wie zu sagen, dass jede Sprache, deren Compiler eine JUMP-Anweisung erzeugt, eine goto-Anweisung hat.
Zombies

4
Sie interviewen also eher auf Java-Trivia als auf der Fähigkeit, Probleme zu lösen und Entwürfe zu durchdenken. Ich werde sicherstellen, dass ich nie mit Ihrer Firma interviewe. :)
Javid Jamae

144

Wie wäre es mit kovarianten Rückgabetypen, die seit JDK 1.5 vorhanden sind? Es ist ziemlich schlecht bekannt, da es eine unsexy Ergänzung ist, aber wie ich es verstehe, ist es absolut notwendig, dass Generika funktionieren.

Im Wesentlichen erlaubt der Compiler jetzt einer Unterklasse, den Rückgabetyp einer überschriebenen Methode auf eine Unterklasse des Rückgabetyps der ursprünglichen Methode zu beschränken. Das ist also erlaubt:

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

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

Sie können die die Unterklasse aufrufen valuesVerfahren und eine sortierte Thread - sicher erhalten Setvon Strings , ohne nach unten gegossen, die auf die ConcurrentSkipListSet.


Können Sie ein Beispiel für eine Verwendung angeben?
Allain Lalonde

24
Ich benutze das oft. clone () ist ein gutes Beispiel. Es soll Object zurückgeben, was bedeutet, dass Sie zB (List) list.clone () sagen müssen. Wenn Sie jedoch als List clone () {...} deklarieren, ist die Umwandlung nicht erforderlich.
Jason Cohen

142

Die Übertragung der Kontrolle in einem finally-Block wirft jede Ausnahme weg. Der folgende Code löst keine RuntimeException aus - er geht verloren.

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

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


7
Es ist böse, aber es ist auch nur eine logische Konsequenz dafür, wie es endlich funktioniert. Die Flusssteuerung try / catch / finally macht das, was beabsichtigt ist, jedoch nur innerhalb bestimmter Grenzen. Ebenso müssen Sie darauf achten, keine Ausnahme innerhalb eines catch / finally-Blocks zu verursachen, oder Sie werfen auch die ursprüngliche Ausnahme weg. Und wenn Sie eine system.exit () innerhalb des try-Blocks ausführen, wird der finally-Block nicht aufgerufen. Wenn Sie den normalen Fluss brechen, brechen Sie den normalen Fluss ...
Neil Coffey

Verwenden Sie nicht endgültig {return; } aber nur endlich {Code ohne Rückgabe}. Dies ist logisch, da schließlich auch ausgeführt werden soll, wenn Ausnahmen aufgetreten sind, und die einzig mögliche Bedeutung einer Rückgabe als Ausnahmebehandlungsroutine darin bestehen muss, die Ausnahme zu ignorieren und - tatsächlich - zurückzugeben.
Extraneon

21
Dies scheint eher ein "Gotcha" als ein verstecktes Feature zu sein, obwohl es Möglichkeiten gibt, es als eines zu verwenden, wäre die Verwendung dieser Methode keine gute Idee.
Davenpcj

Eclipse gibt eine Warnung aus, wenn Sie dies tun. Ich bin bei Eclipse. Wenn Sie eine Ausnahme abfangen möchten ... dann fangen Sie eine Ausnahme ab.
Helios

Das ist es, was Sie für schmutzigen Code bezahlen, der aus der Mitte der Methode zurückkehrt. Aber immer noch ein schönes Beispiel.
Rostislav Matl

141

Ich habe noch niemanden gesehen, der eine Instanz der Implementierung so erwähnt hat, dass eine Überprüfung auf Null nicht erforderlich ist.

Anstatt:

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

benutz einfach:

if( aObject instanceof String )
{
    ...
}

9
Es ist eine Schande, dass dies eine so wenig bekannte Funktion ist. Ich habe viel Code gesehen, der dem ersten Codeblock ähnelt.
Peter Dolberg

4
Dies liegt daran, dass Java einen speziellen (versteckten) Nulltyp hat, den Sie weder sehen noch referenzieren können.
Nick Hristov

Noch schlimmer ist , für null Überprüfung vor freeing oder deleteing in C / C ++. Solch ein grundlegendes Konzept.
Thomas Eding

134

Das Zulassen von Methoden und Konstruktoren in Aufzählungen hat mich überrascht. Zum Beispiel:

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

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

Sie können sogar einen "konstanten spezifischen Klassenkörper" haben, der es einem bestimmten Enum-Wert ermöglicht, Methoden zu überschreiben.

Weitere Dokumentation hier .


20
Wirklich großartige Funktion - macht Enums OO und löst viele Initialisierungsprobleme auf sehr saubere Weise.
Bill K

5
Aufzählung als Singleton? Aufzählung mit nur einem Wert?
Georgy Bolyuba

6
Georgy: Singleton ist eine Instanz des Objekts, kein Objekt mit einem Wert.
Dshaw

20
@Georgy: siehe auch Punkt 3 in Joshua Blochs Effective Java (2. Ausgabe); "Obwohl dieser Ansatz noch nicht weit verbreitet ist, ist ein Aufzählungstyp mit einem Element der beste Weg, um einen Singleton zu implementieren."
Jonik

3
Kleiner Nitpick: mAgesollte endgültig sein. Es gibt selten einen Grund für nicht endgültige Felder in Aufzählungen.
Joachim Sauer

121

Die Typparameter für generische Methoden können explizit wie folgt angegeben werden:

Collections.<String,Integer>emptyMap()

10
Und bei Gott ist es hässlich und verwirrend. Und für die Typensicherheit irrelevant.
Chris Broadfoot

8
Ich liebe es. Es macht Ihren Code ein bisschen expliziter und als solcher klarer für den armen Kerl, der ihn in ein oder zwei Jahren warten muss.
Extraneon

6
Dies ist in Situationen, in denen Sie eine statische generische Methode deklariert haben, wie z public static <T> T foo(T t). Sie können dann anrufenClass.<Type>foo(t);
Finbarr

Aus irgendeinem Grund scheint dies mit statisch importierten Methoden nicht zu funktionieren. Ich frage mich, warum.
Oksayt

Dies ist besonders nützlich, wenn Sie ternäre ifs mit einer Rückgabe verwenden. Zum Beispiel return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList(). Dies ist auch nützlich für einige Methodenaufrufe, bei denen eine einfache Collections.emptyMap () einen Kompilierungsfehler ergibt.
Andreas Holstenson

112

Sie können Aufzählungen verwenden, um eine Schnittstelle zu implementieren.

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

EDIT: Jahre später ....

Ich benutze diese Funktion hier

public enum AffinityStrategies implements AffinityStrategy {

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

Mithilfe einer Schnittstelle können Entwickler ihre eigenen Strategien definieren. Mit einem enumMittel kann ich eine Sammlung von fünf integrierten definieren.


27
Das ist Wahnsinn. (+1)
Kopffüßer

12
@Arian das ist kein Wahnsinn. DIES. IS. JAVAAAAAAHHHH!
Slezica

1
WHAAAAAT nein, ich bin bei Adrian. Dies ist kein Java. Das ist Wahnsinn. Ich möchte das unbedingt benutzen.
Slezica

104

Ab Java 1.5 verfügt Java nun über eine viel sauberere Syntax zum Schreiben von Funktionen mit variabler Arität. Anstatt nur ein Array zu übergeben, können Sie jetzt Folgendes tun

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

Balken werden automatisch in ein Array des angegebenen Typs konvertiert. Kein großer Gewinn, aber dennoch ein Gewinn.


23
Das Wichtigste dabei ist, dass Sie beim Aufrufen der Methode schreiben können: foo ("erste", "zweite", "dritte")
Steve Armstrong

9
so kann die alte hallo welt umgeschrieben werden; public static void main (String ... args) {System.out.println ("Hallo Welt!"); }
Karussell

@ Karussell Vielleicht, aber es scheint, dass die Argumente irrelevant sind: p
Kelly Elton

93

Mein Favorit: Alle Thread-Stack-Traces auf Standard ausgeben.

Windows: CTRL- BreakIn Ihrem Java-Cmd / Konsolenfenster

Unix: kill -3 PID


15
Auch Strg- \ in Unix. Oder verwenden Sie jstack aus dem JDK.
Tom Hawtin - Tackline

9
Danke, du hast mir gerade beigebracht, dass meine Tastatur eine BreakTaste hat.
Amy B

2
Unter Windows funktioniert STRG-BREAK nur, wenn der Prozess im aktuellen Konsolenfenster ausgeführt wird. Sie können stattdessen JAVA_HOME / bin / jstack.exe verwenden. Geben Sie einfach die Windows-Prozess-ID ein.
Javid Jamae

Ich dachte, es wäre töten
Nick Hristov

@ Nick, ja SIGQUIT ist normalerweise Signal # 3.
Chris Mazzola

89

Einige Leute haben über Instanzinitialisierer geschrieben. Hier ist eine gute Verwendung dafür:

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

Ist eine schnelle Möglichkeit, Karten zu initialisieren, wenn Sie nur schnell und einfach etwas tun.

Oder verwenden Sie es, um einen schnellen Swing-Frame-Prototyp zu erstellen:

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

Natürlich kann es missbraucht werden:

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

Irgendwie ist es ein bisschen so, als ob Java das Schlüsselwort "with" (eigentlich Funktionalität) hinzugefügt wurde. Kann sehr praktisch sein, vor kurzem grunzte ich, weil die Initialisierung von Arrays für Sammlungen nicht verfügbar war. Vielen Dank!
PhiLho

15
Es gibt jedoch einen Nebeneffekt bei der Verwendung. Es werden anonyme Objekte erstellt, die möglicherweise nicht immer in Ordnung sind.
Amit

17
Obwohl ich, nachdem ich es mir genauer angesehen habe, sagen muss, dass ich mich seltsamerweise von der natürlichen Verschachtelung angezogen fühle, die dies bietet, selbst von der "Missbrauchten" Version.
Bill K

4
Ja - ich mag die "missbrauchte" Version sehr, ich denke, das ist wirklich sehr klar und lesbar, aber vielleicht bin das nur ich.
Barryred

3
Absolut einverstanden, die Hierarchie des Codes, die die Hierarchie der GUI widerspiegelt, ist eine enorme Verbesserung gegenüber einer Folge von Methodenaufrufen.
opsb

88

Mit dynamischen Proxys (hinzugefügt in 1.3) können Sie zur Laufzeit einen neuen Typ definieren, der einer Schnittstelle entspricht. Es hat sich überraschend oft als nützlich erwiesen.


10
Dynamische Proxys sind ein guter Grund, eine Foo-Schnittstelle zu schreiben und diese überall mit einer Standardklasse "FooImpl" zu verwenden. Es mag zunächst hässlich erscheinen ("Warum nicht einfach eine Klasse namens Foo?"), Aber die Vorteile in Bezug auf zukünftige Flexibilität und Verspottungsfähigkeit für Komponententests sind praktisch. Es gibt zwar Möglichkeiten, dies auch für Nicht-Schnittstellen zu tun, sie erfordern jedoch normalerweise zusätzliche Dinge wie cblib.
Darien

82

Die endgültige Initialisierung kann verschoben werden.

Es stellt sicher, dass auch bei einem komplexen Fluss logischer Rückgabewerte immer Werte festgelegt werden. Es ist zu leicht, einen Fall zu übersehen und versehentlich null zurückzugeben. Es macht es nicht unmöglich, null zurückzugeben, nur offensichtlich, dass es absichtlich ist:

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

Das ist überraschend. Kann man fair sagen: "Der Wert einer endgültigen Variablen kann einmal gesetzt werden", unabhängig davon, wo die Menge auftritt?
David Koelle

29
Ja, aber stärker: "Der Wert einer endgültigen Variablen muss einmal gesetzt werden"
Allain Lalonde

6
+1 Stimmen Sie zu, dies ist ein weiteres wertvolles Tool zum Erkennen von Fehlern beim Kompilieren, das Programmierer aus irgendeinem Grund schüchtern zu verwenden scheinen. Beachten Sie, dass 'final' ab Java 5 auch Auswirkungen auf die Thread-Sicherheit hat und es von unschätzbarem Wert ist, eine endgültige Variable während des Konstruktors festzulegen.
Neil Coffey

4
Für diese spezielle Methode würde ich jedoch nur mehrere Rückgaben verwenden. In den meisten Fällen, in denen dies zutrifft, würde ich es wahrscheinlich in eine separate Methode umgestalten und mehrere Rückgaben verwenden.
Ripper234

Ich liebe es! Ich habe das letzte Schlüsselwort immer gelöscht, weil ich dachte, dass es fehlschlagen wird. Vielen Dank!
KARASZI István

62

Ich denke, ein weiteres "übersehenes" Feature von Java ist die JVM selbst. Es ist wahrscheinlich die beste verfügbare VM. Und es unterstützt viele interessante und nützliche Sprachen (Jython, JRuby, Scala, Groovy). Alle diese Sprachen können einfach und nahtlos zusammenarbeiten.

Wenn Sie eine neue Sprache entwerfen (wie im Scala-Fall), stehen Ihnen sofort alle vorhandenen Bibliotheken zur Verfügung, und Ihre Sprache ist daher von Anfang an "nützlich".

Alle diese Sprachen nutzen die HotSpot-Optimierungen. Die VM ist sehr gut zu überwachen und zu debuggen.


18
Nein, es ist eigentlich keine sehr gute VM. Es wurde ausschließlich für JAVA entwickelt. Typlose dynamische und funktionale Sprachen funktionieren damit nicht gut. Wenn Sie eine VM verwenden möchten, sollten Sie .NET / Mono verwenden. Das wurde entwickelt, um mit JEDER Sprache zu arbeiten ...
Hades32

14
Tatsächlich ist die JVM ausschließlich für die Ausführung von Java-Bytecodes ausgelegt. Sie können die meisten modernen Sprachen zu Java Bytecode kompilieren. Das einzige, was Java Bytecode fehlt, ist die Unterstützung für dynamische Sprache, Zeiger und Unterstützung für die Schwanzrekursion.
Mcjabberz

12
@ Hades32: Eigentlich ist die .NET VM der JVM ziemlich ähnlich. Dynamische Sprachen wurden erst vor relativ kurzer Zeit (mit dem DLR) unterstützt, und Java 7 wird diese Unterstützung ebenfalls erhalten. Und die klassische "JEDE Sprache" von .NET (C #, Visual Basic.NET, ...) hat alle ziemlich genau den gleichen Funktionsumfang.
Joachim Sauer

13
JVM unterstützt keine Generika, während die .NET-VM dies tut. JVM ist bei weitem nicht das Beste.
Blindy

3
Um die Beschwerden über bestimmte Sprachfunktionen, die nicht direkt von der JVM unterstützt werden, nicht auszuschließen, denke ich, dass Stabilität, plattformübergreifende Konsistenz und gute Leistung weit über den Gründen liegen, aus denen die JVM zusätzliche Punkte erhält. Ich arbeite seit vielen Jahren mit serverseitigem Java auf vielen Plattformen (einschließlich AS / 400) und konnte es so gut wie vollständig vergessen - die Fehler sind so gut wie immer in Code enthalten, den ich beheben kann, und das auch stürzt einfach nicht ab.
Rob Whelan

58

Sie können eine anonyme Unterklasse definieren und direkt eine Methode darauf aufrufen, auch wenn keine Schnittstellen implementiert sind.

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

@Vuntic - Hiermit können Sie eine einfache Klasse in dem Kontext definieren, in dem sie benötigt wird.
ChaosPandion

1
@Chaos, aber warum? Haben Sie ein aktuelles Beispiel, wo es nützlich ist?
Thorbjørn Ravn Andersen

10
@Wouter - In diesem Fall ist die Methode, die für das anonyme Objekt ( start()) aufgerufen wird, nicht in der Unterklasse definiert ...
Axel

Tatsächlich ist dies eine sehr nützliche Funktion, wenn Sie eine Basisklasse erweitern, die einige erforderliche Einstellungen vornimmt, die von Ihnen geschriebene Methode aufruft und dann herunterfährt. Starten Sie das Ding, indem Sie eine Methode in der Basisklasse aufrufen (die ich wahrscheinlich nicht mit demselben Namen versehen würde). Es gibt ein Beispiel Verwendung (nicht Definition) hier
AmigoNico

56

Die asList- Methode in java.util.Arraysermöglicht eine schöne Kombination von Varargs, generischen Methoden und Autoboxing:

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

15
Sie möchten die zurückgegebene Liste mit einem Listenkonstruktor umschließen, andernfalls haben Ints eine feste Größe (da sie vom Array unterstützt werden)
KitsuneYMG

2
Das Arrays.asListhat die ungewöhnliche Funktion, dass Sie set()Elemente aber nicht add()oder können remove(). Daher wickle ich es normalerweise in ein new ArrayList(...)oder in ein Collections.unmodifiableList(...), je nachdem, ob die Liste geändert werden soll oder nicht.
Christian Semrau

53

Verwenden dieses Schlüsselworts für den Zugriff auf Felder / Methoden zum Enthalten von Klassen aus einer inneren Klasse. Im folgenden, eher konstruierten Beispiel möchten wir das sortAscending-Feld der Containerklasse aus der anonymen inneren Klasse verwenden. Die Verwendung von ContainerClass.this.sortAscending anstelle von this.sortAscending reicht aus.

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
Dies ist nur erforderlich, wenn Sie den Namen (in Ihrem Fall mit dem Namen des Methodenparameters) beschattet haben. Wenn Sie das Argument etwas anderes genannt haben, können Sie direkt auf die sortAscending-Mitgliedsvariable der Container-Klasse zugreifen, ohne 'this' zu verwenden.
sk.

7
Es ist immer noch nützlich, einen Verweis auf die einschließende Klasse zu haben, z. wenn Sie es an eine Methode oder einen Construtor übergeben müssen.
PhiLho

Wird häufig in der Android-Layoutentwicklung verwendet, um den Kontext beispielsweise vom Hörer einer Schaltfläche mit abzurufen MyActivity.this.
Espinchi

52

Nicht wirklich eine Funktion, aber ein amüsanter Trick, den ich kürzlich auf einer Webseite entdeckt habe:

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

    System.exit(0);
  }
}

ist ein gültiges Java-Programm (obwohl es eine Warnung generiert). Wenn Sie nicht verstehen, warum, lesen Sie Gregorys Antwort! ;-) Nun, die Syntaxhervorhebung hier gibt auch einen Hinweis!


15
ordentlich, ein Etikett mit einem Kommentar :)
Thorbjørn Ravn Andersen

46

Dies ist nicht gerade "versteckte Funktionen" und nicht sehr nützlich, kann aber in einigen Fällen äußerst interessant sein:
Klasse sun.misc.Unsafe - ermöglicht die Implementierung der direkten Speicherverwaltung in Java (Sie können sogar selbstmodifizierenden Java-Code mit schreiben dies, wenn Sie viel versuchen):

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
das ist eine Sonne. * API, die nicht wirklich Teil der Java-Sprache an sich ist
DW.

Es gibt eine Reihe anderer merkwürdiger Methoden in Unsafe, wie das Erstellen eines Objekts ohne Aufruf eines Konstruktors, malloc / realloc / free style-Methoden.
Peter Lawrey

Ich liebe besonders die primitiven Getter und Setter an Speicherorten wie putDouble (lange Adresse, doppeltes d).
Daniel

42

Wenn ich in Swing arbeite, mag ich die versteckte Ctrl- Shift- F1Funktion.

Der Komponentenbaum des aktuellen Fensters wird ausgegeben.
(Angenommen, Sie haben diesen Tastendruck nicht an etwas anderes gebunden.)


1
Höchstwahrscheinlich hat Ihr Fenstermanager etwas an diesen Schlüssel gebunden. Gnome bindet nicht daran, daher gehe ich davon aus, dass Sie KDE ausführen, das es an 'Switch to Desktop 13' bindet. Sie können es ändern, indem Sie zu Systemsteuerung, Regional, Tastaturkürzel gehen und die Zuordnung für Umschalt-Strg-F1
Devon_C_Miller

40

Jede Klassendatei beginnt mit dem Hex-Wert 0xCAFEBABE , um sie als gültigen JVM-Bytecode zu identifizieren.

( Erklärung )


38

Meine Stimme geht an java.util.concurrent mit seinen gleichzeitigen Sammlungen und flexiblen Ausführenden, die unter anderem Thread-Pools, geplante Aufgaben und koordinierte Aufgaben ermöglichen. Die DelayQueue ist mein persönlicher Favorit, bei dem Elemente nach einer bestimmten Verzögerung verfügbar gemacht werden.

java.util.Timer und TimerTask können sicher zur Ruhe gesetzt werden.

Auch nicht genau versteckt, sondern in einem anderen Paket als die anderen Klassen in Bezug auf Datum und Uhrzeit. java.util.concurrent.TimeUnit ist nützlich beim Konvertieren zwischen Nanosekunden, Mikrosekunden, Millisekunden und Sekunden.

Es liest sich viel besser als der übliche someValue * 1000 oder someValue / 1000.


Kürzlich entdeckt CountDownLatchund CyclicBarrier- so nützlich!
Raphael

37

Sprachebene assert Stichwort.


19
Das Problem mit Assert ist, dass es zur Laufzeit eingeschaltet werden muss.
Extraneon

10
Aber wenn es deaktiviert ist, ist es so, als wäre es nicht da. Sie können so viele Asserts hinzufügen, wie Sie möchten, und Sie haben keine Leistungseinbußen, wenn sie deaktiviert sind.
Ravi Wallau

5
Ich glaube, das ist eine gute Sache bei der Behauptung: Sie kann ohne Strafe ausgeschaltet werden.
andref

Das Problem ist, wenn Sie versehentlich einen Nebeneffekt in einer Behauptung implementiert haben, müssen Sie die Behauptung aktivieren, damit Ihr Programm funktioniert ...
Chii

Um festzustellen, ob Asserts aktiviert sind, können Sie {boolean assertsOn = false; assert assertsOn = true; if (assertsOn) {/ * komplexe Überprüfung * /}}. Dies ermöglicht auch das Protokollieren oder Auslösen einer Ausnahme, wenn der Status der Bestätigung nicht dem erwarteten entspricht.
Fernacolo

37

Nicht wirklich Teil der Java-Sprache, aber der Javap-Disassembler, der mit Suns JDK geliefert wird, ist nicht allgemein bekannt oder wird nicht verwendet.


36

Die Hinzufügung des for-each-Schleifenkonstrukts in 1.5. Ich <3 es.

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

Und kann in verschachtelten Instanzen verwendet werden:

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

Das for-each-Konstrukt gilt auch für Arrays, in denen die Indexvariable und nicht der Iterator ausgeblendet werden. Die folgende Methode gibt die Summe der Werte in einem int-Array zurück:

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

Link zur Sun-Dokumentation


30
Ich denke, die Verwendung ihier ist sehr verwirrend, da die meisten Leute erwarten, dass ich ein Index und nicht das Array-Element bin .
CDMckay

Also ... int sum (int [] array) {int result = 0; für (int element: array) {result + = element; } return result; }
Drew

28
Das einzige, was mich verrückt macht, ist, dass es wirklich sehr einfach zu erstellen scheint, ein Schlüsselwort für den Zugriff auf den Loop-Count-Wert zu erstellen, aber das können Sie nicht. Wenn ich zwei Arrays durchlaufen und Änderungen an einer Sekunde basierend auf den Werten im ersten vornehmen möchte, muss ich die alte Syntax verwenden, da ich keinen Offset im zweiten Array habe.
Jherico

6
Es ist eine Schande, dass es nicht auch mit Aufzählungen funktioniert, wie sie in JNDI verwendet werden. Dort geht es zurück zu den Iteratoren.
Extraneon

3
@extraneon: Schauen Sie sich Collections.list (Enumeration <T> e) an. Dies sollte bei der Iteration von Aufzählungen in der foreach-Schleife hilfreich sein.
Werner Lehmann

34

Ich persönlich habe es java.lang.Voidsehr spät entdeckt - verbessert die Lesbarkeit des Codes in Verbindung mit Generika, zCallable<Void>


2
nicht ganz. Irgendwann müssen Sie spezifisch sein: Executors.newSingleThreadExecutor (). submit (new Callable <Void> () {..}) - Sie können kein neues Callable <?> () instanziieren, das Sie angeben müssen ein expliziter Typ - daher ist es eine Alternative zu Callable <Object>.
Rahel Lüthy

4
Void ist spezifischer als Object, da Void nur null sein kann, Object kann alles sein.
Peter Lawrey
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.