Dopo aver letto Hidden Features of C #, mi chiedevo, quali sono alcune delle funzionalità nascoste di Java?
Dopo aver letto Hidden Features of C #, mi chiedevo, quali sono alcune delle funzionalità nascoste di Java?
Risposte:
Inizializzazione doppia parentesi graffa mi ha sorpreso alcuni mesi fa quando l'ho scoperto per la prima volta, non ne avevo mai sentito parlare prima.
ThreadLocals è in genere così ampiamente noto come un modo per memorizzare lo stato per thread.
Dato che JDK 1.5 Java ha implementato strumenti di concorrenza estremamente ben implementati e robusti oltre ai semplici blocchi, vive in java.util.concurrent e un esempio particolarmente interessante è il subpackage java.util.concurrent.atomic che contiene primitive thread-safe che implementano il confronto -e scambiare operazioni e può mappare alle versioni supportate dall'hardware nativo di queste operazioni.
Unione unita nella varianza dei parametri di tipo:
public class Baz<T extends Foo & Bar> {}
Ad esempio, se vuoi prendere un parametro che è sia Comparable che una Collection:
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);
}
Questo metodo inventato restituisce true se le due raccolte indicate sono uguali o se una di esse contiene l'elemento dato, altrimenti false. Il punto da notare è che è possibile richiamare metodi di Comparable e Collection sugli argomenti b1 e b2.
Sono stato sorpreso dagli inizializzatori dell'istanza l'altro giorno. Stavo eliminando alcuni metodi piegati a codice e ho finito per creare inizializzatori a più istanze:
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");
}
}
L'esecuzione del main
metodo visualizzerà:
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
Immagino che questi sarebbero utili se avessi più costruttori e avessi bisogno di un codice comune
Forniscono anche zucchero sintattico per inizializzare le tue classi:
List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};
Map<String,String> codes = new HashMap<String,String>(){{
put("1","one");
put("2","two");
}};
JDK 1.6_07 + contiene un'app chiamata VisualVM (bin / jvisualvm.exe) che è una bella GUI su molti degli strumenti. Sembra più completo di JConsole.
Caratteri jolly del classpath da Java 6.
java -classpath ./lib/* so.Main
Invece di
java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main
Vedi http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html
Per la maggior parte delle persone che intervisto per le posizioni degli sviluppatori Java, i blocchi etichettati sono molto sorprendenti. Ecco un esempio:
// 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;
}
}
}
}
Chi ha detto che goto
Java è solo una parola chiave? :)
Che ne dite di tipi di ritorno covarianti che sono stati in atto dal JDK 1.5? È scarsamente pubblicizzato, in quanto è un'aggiunta nonxy, ma a quanto ho capito, è assolutamente necessario per far funzionare i generici.
In sostanza, il compilatore ora consente a una sottoclasse di restringere il tipo restituito di un metodo sostituito per essere una sottoclasse del tipo restituito del metodo originale. Quindi questo è permesso:
class Souper {
Collection<String> values() {
...
}
}
class ThreadSafeSortedSub extends Souper {
@Override
ConcurrentSkipListSet<String> values() {
...
}
}
È possibile chiamare il values
metodo della sottoclasse e ottenere un thread ordinato sicuro Set
di String
s senza dover eseguire il down cast del ConcurrentSkipListSet
.
Il trasferimento del controllo in un blocco finalmente elimina qualsiasi eccezione. Il seguente codice non genera RuntimeException - è perso.
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;
}
}
Da http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
Non ho mai visto nessuno menzionare l'istanza di essere implementata in modo tale da non essere necessario controllare null.
Invece di:
if( null != aObject && aObject instanceof String )
{
...
}
basta usare:
if( aObject instanceof String )
{
...
}
free
inserire o delete
inserire in C / C ++. Un concetto così fondamentale.
Consentire metodi e costruttori negli enum mi ha sorpreso. Per esempio:
enum Cats {
FELIX(2), SHEEBA(3), RUFUS(7);
private int mAge;
Cats(int age) {
mAge = age;
}
public int getAge() {
return mAge;
}
}
Puoi anche avere un "corpo di classe specifico costante" che consente a un valore enum specifico di sovrascrivere i metodi.
Più documentazione qui .
mAge
dovrebbe essere definitivo. Raramente c'è un motivo per feld non definitivi negli enum.
I parametri di tipo per metodi generici possono essere specificati in modo esplicito in questo modo:
Collections.<String,Integer>emptyMap()
public static <T> T foo(T t)
. È quindi possibile effettuare chiamate aClass.<Type>foo(t);
return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList()
. È utile anche per alcune invocazioni di metodi in cui un semplice Collections.emptyMap () darebbe un errore di compilazione.
Puoi usare enum per implementare un'interfaccia.
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: anni dopo ....
Uso questa funzione qui
public enum AffinityStrategies implements AffinityStrategy {
Utilizzando un'interfaccia, gli sviluppatori possono definire le proprie strategie. Usando un enum
mezzo posso definire una raccolta (di cinque) incorporata in quelle.
A partire da Java 1.5, Java ora ha una sintassi molto più pulita per la scrittura di funzioni di arity variabile. Quindi, invece di passare semplicemente un array, ora puoi fare quanto segue
public void foo(String... bars) {
for (String bar: bars)
System.out.println(bar);
}
le barre vengono convertite automaticamente in array del tipo specificato. Non una vittoria enorme, ma comunque una vittoria.
Il mio preferito: eseguire il dump di tutte le tracce dello stack di thread allo standard out.
windows: CTRL- Breaknella finestra java cmd / console
unix: kill -3 PID
Break
chiave.
Un paio di persone hanno pubblicato degli inizializzatori di istanze, ecco un buon uso per questo:
Map map = new HashMap() {{
put("a key", "a value");
put("another key", "another value");
}};
È un modo rapido per inizializzare le mappe se stai semplicemente facendo qualcosa di semplice e veloce.
O utilizzandolo per creare un prototipo di telaio a battente rapido:
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 );
Naturalmente può essere abusato:
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");
}
});
}});
}});
}};
I proxy dinamici (aggiunti in 1.3) consentono di definire un nuovo tipo in fase di esecuzione conforme a un'interfaccia. È utile un numero sorprendente di volte.
l'inizializzazione finale può essere posticipata.
Si assicura che anche con un flusso complesso di valori di ritorno logici siano sempre impostati. È troppo facile perdere un caso e restituire null per caso. Non rende impossibile il ritorno null, solo ovvio che è apposta:
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;
}
Penso che un'altra caratteristica "trascurata" di Java sia la stessa JVM. È probabilmente la migliore VM disponibile. E supporta molte lingue interessanti e utili (Jython, JRuby, Scala, Groovy). Tutte queste lingue possono cooperare facilmente e senza soluzione di continuità.
Se si progetta una nuova lingua (come nello scala-case), si dispone immediatamente di tutte le librerie esistenti e la lingua è quindi "utile" sin dall'inizio.
Tutte queste lingue utilizzano le ottimizzazioni di HotSpot. La VM è molto ben monitorata e debuggabile.
È possibile definire una sottoclasse anonima e chiamare direttamente un metodo su di essa anche se non implementa interfacce.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
start()
) non è in realtà definito nella sottoclasse ...
Il metodo asList in java.util.Arrays
consente una buona combinazione di vararg, metodi generici e autoboxing:
List<Integer> ints = Arrays.asList(1,2,3);
Arrays.asList
ha la particolarità che si può set()
elementi, ma non add()
o remove()
. Quindi di solito lo avvolgo in a new ArrayList(...)
o in a Collections.unmodifiableList(...)
, a seconda che si desideri modificare l'elenco o meno.
Utilizzo di questa parola chiave per accedere a campi / metodi per contenere la classe da una classe interna. Nell'esempio che segue, piuttosto ingegnoso, vogliamo usare il campo sortAscending della classe container dalla classe interna anonima. L'uso di ContainerClass.this.sortAscending invece di this.sortAscending fa il trucco.
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;
}
}
MyActivity.this
.
Non proprio una funzionalità, ma un trucco divertente che ho scoperto di recente in alcune pagine Web:
class Example
{
public static void main(String[] args)
{
System.out.println("Hello World!");
http://Phi.Lho.free.fr
System.exit(0);
}
}
è un programma Java valido (anche se genera un avviso). Se non vedi il perché, vedi la risposta di Gregory! ;-) Bene, l'evidenziazione della sintassi qui dà anche un suggerimento!
Non si tratta esattamente di "funzioni nascoste" e non molto utili, ma in alcuni casi può essere estremamente interessante:
Class sun.misc.Unsafe - ti permetterà di implementare la gestione diretta della memoria in Java (puoi persino scrivere codice Java auto-modificante con questo se ci provi molto):
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);
}
};
}
Quando lavoro in Swing mi piace il nascosto Ctrl- Shift-F1 funzione.
Scarica l'albero dei componenti della finestra corrente.
(Supponendo di non aver vincolato la sequenza di tasti a qualcos'altro.)
Ogni file di classe inizia con il valore esadecimale 0xCAFEBABE per identificarlo come bytecode JVM valido.
( Spiegazione )
Il mio voto va a java.util.concurrent con le sue raccolte simultanee e gli esecutori flessibili che consentono tra l'altro pool di thread, attività pianificate e attività coordinate. Il DelayQueue è il mio preferito personale, in cui gli elementi vengono resi disponibili dopo un determinato ritardo.
java.util.Timer e TimerTask possono essere tranquillamente messi a riposo.
Inoltre, non esattamente nascosto ma in un pacchetto diverso dalle altre classi relative a data e ora. java.util.concurrent.TimeUnit è utile per la conversione tra nanosecondi, microsecondi, millisecondi e secondi.
Legge molto meglio del solito someValue * 1000 o someValue / 1000.
CountDownLatch
e CyclicBarrier
- così utile!
Parola chiave di asserzione a livello di lingua .
In realtà non fa parte del linguaggio Java, ma il disassemblatore javap fornito con il JDK di Sun non è ampiamente conosciuto o utilizzato.
L'aggiunta del costrutto loop for-each in 1.5. I <3 esso.
// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
System.out.println(foo.toString());
}
E può essere utilizzato in istanze nidificate:
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
Il costrutto for-each è applicabile anche alle matrici, in cui nasconde la variabile indice anziché l'iteratore. Il seguente metodo restituisce la somma dei valori in una matrice int:
// Returns the sum of the elements of a
int sum(int[] a) {
int result = 0;
for (int i : a)
result += i;
return result;
}
i
qui sia molto confuso, poiché la maggior parte delle persone si aspetta che io sia un indice e non l'elemento array.
l'ho scoperto personalmente java.lang.Void
molto tardi - migliora la leggibilità del codice insieme ai generici, ad esCallable<Void>