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?

grom
quelle
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.

Boris Terzic
quelle
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.

Apocalisp
quelle
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");
}};
David Carlson
quelle
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.

Kevin Wong
quelle
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? :) :)

Georgy Bolyuba
quelle
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.

serg10
quelle
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

James AN Stauffer
quelle
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 )
{
    ...
}
Kadett Pirx
quelle
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 .

Adrian Mouat
quelle
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()
Kevin Wong
quelle
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.

Peter Lawrey
quelle
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.

Paul Wicks
quelle
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

Chris Mazzola
quelle
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");
                        }
                     });
                 }});
        }});
    }};
OscarRyz
quelle
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.

Jodonnell
quelle
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;
}
Allain Lalonde
quelle
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.

Mo.
quelle
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");
Ron
quelle
@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);
Bruno De Fraine
quelle
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;
}
}
Tahir Akhtar
quelle
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!

PhiLho
quelle
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);
        }
    };
}
Das
quelle
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.)

Devon_C_Miller
quelle
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 )

Dolph
quelle
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.

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

Sprachebene assert Stichwort.

Mark Cidade
quelle
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.

Binil Thomas
quelle
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

18Rabbit
quelle
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>

Rahel Lüthy
quelle
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