Caratteristiche nascoste di Java
Dopo aver letto Caratteristiche nascoste di c# mi sono chiesto, Quali sono alcune delle caratteristiche nascoste di Java?
30 answers
L'inizializzazione della doppia parentesi graffa mi ha colto di sorpresa qualche mese fa, quando l'ho scoperta per la prima volta, non ne ho mai sentito parlare prima.
ThreadLocals non sono in genere così ampiamente conosciuti come un modo per memorizzare lo stato per thread.
Dal momento che JDK 1.5 Java ha avuto strumenti di concorrenza estremamente ben implementati e robusti oltre ai semplici blocchi, vivono in java.util.concurrent e un esempio particolarmente interessante è java.util.simultaneo.subpackage atomico che contiene primitive thread-safe che implementano l'operazione compare-and-swap e possono essere mappate alle versioni di queste operazioni supportate dall'hardware nativo.
Unione congiunta nella varianza dei parametri di tipo:
public class Baz<T extends Foo & Bar> {}
Ad esempio, se si desidera prendere un parametro che sia sia comparabile che una raccolta:
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 artificioso restituisce true se le due raccolte date sono uguali o se una di esse contiene l'elemento dato, altrimenti false. Il punto da notare è che è possibile richiamare metodi sia Comparabili che di raccolta sugli argomenti b1 e b2.
Sono rimasto sorpreso dagli inizializzatori di istanze l'altro giorno. Stavo cancellando alcuni metodi piegati in codice e ho finito per creare più inizializzatori di 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 metodo main
mostrerà:
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 codice comune
Forniscono anche zucchero sintattico per inizializzare le 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) questa è una bella GUI in cima a molti degli strumenti. Sembra più completo di JConsole.
Classpath jolly 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
Vedere http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html
Per la maggior parte delle persone che intervista 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
in java è solo una parola chiave? :)
Che ne dici di tipi di ritorno covarianti che sono in vigore da JDK 1.5? È piuttosto poco pubblicizzato, in quanto è un'aggiunta poco sexy, ma a quanto ho capito, è assolutamente necessario che i generici funzionino.
Essenzialmente, il compilatore ora consente a una sottoclasse di restringere il tipo di ritorno di un metodo sovrascritto per essere una sottoclasse del tipo di ritorno del metodo originale. Quindi questo è permesso:
class Souper {
Collection<String> values() {
...
}
}
class ThreadSafeSortedSub extends Souper {
@Override
ConcurrentSkipListSet<String> values() {
...
}
}
È possibile chiamare il metodo values
della sottoclasse e ottenere un thread ordinato sicuro Set
di String
s senza dover down cast al ConcurrentSkipListSet
.
Non ho visto nessuno menzionare instanceof implementato in modo tale che il controllo di null non sia necessario.
Invece di:
if( null != aObject && aObject instanceof String )
{
...
}
Basta usare:
if( aObject instanceof String )
{
...
}
Il trasferimento del controllo in un blocco finally 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
Consentire metodi e costruttori nelle enumerazioni mi ha sorpreso. Ad esempio:
enum Cats {
FELIX(2), SHEEBA(3), RUFUS(7);
private int mAge;
Cats(int age) {
mAge = age;
}
public int getAge() {
return mAge;
}
}
Puoi persino avere un "corpo di classe specifico costante" che consente a un valore enum specifico di sovrascrivere i metodi.
Più documentazione qui .
I parametri di tipo per i metodi generici possono essere specificati esplicitamente in questo modo:
Collections.<String,Integer>emptyMap()
È possibile utilizzare 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; }
}
MODIFICA: Anni dopo....
Io uso questa funzione qui
public enum AffinityStrategies implements AffinityStrategy {
Utilizzando un'interfaccia, gli sviluppatori possono definire le proprie strategie. Usare un enum
significa che posso definire una collezione (di cinque) costruita in quelle.
A partire da Java 1.5, Java ora ha una sintassi molto più pulita per scrivere funzioni di arity variabile. Quindi, invece di passare solo un array, ora puoi fare quanto segue
public void foo(String... bars) {
for (String bar: bars)
System.out.println(bar);
}
Bars viene automaticamente convertito in array del tipo specificato. Non una grande vittoria, ma una vittoria comunque.
Il mio preferito: scarica tutte le tracce dello stack di thread su standard out.
Finestre: CTRL-Interrompi nella finestra java cmd/console
Unix: kill -3 PID
Un paio di persone hanno pubblicato su 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 solo facendo qualcosa di semplice e veloce.
O usarlo per creare un prototipo di frame swing 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 runtime conforme a un'interfaccia. È tornato utile un numero sorprendente di volte.
L'inizializzazione finale può essere posticipata.
Fa in modo che anche con un flusso complesso di valori di ritorno logica sono sempre impostati. È troppo facile perdere un caso e restituire null per caso. Non rende impossibile restituire 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 JVM stessa. È probabilmente la migliore VM disponibile. E supporta un sacco di lingue interessanti e utili (Jython, JRuby, Scala, Groovy). Tutte queste lingue possono facilmente e senza soluzione di continuità cooperare.
Se si progetta una nuova lingua (come nel caso scala) si hanno immediatamente tutte le librerie esistenti disponibili e la lingua è quindi "utile" fin dall'inizio.
Tutte queste lingue fanno uso dell'HotSpot ottimizzazione. La VM è molto ben monitorata e debuggabile.
È possibile definire una sottoclasse anonima e chiamare direttamente un metodo su di esso anche se non implementa interfacce.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
Il metodo asList in java.util.Arrays
consente una bella combinazione di varargs, metodi generici e autoboxing:
List<Integer> ints = Arrays.asList(1,2,3);
Usando questa parola chiave per accedere ai campi/metodi di contenere la classe da una classe interna. Nell'esempio seguente, piuttosto artificioso, vogliamo utilizzare il campo sortAscending della classe container dalla classe interna anonima. Utilizzando ContainerClass.questo.sortAscending invece di questo.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;
}
}
Non proprio una caratteristica, ma un trucco divertente che ho scoperto di recente in qualche pagina 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 capisci perché, vedi la risposta di Gregory! ;- ) Bene, l'evidenziazione della sintassi qui dà anche un suggerimento!
Questo non è esattamente" caratteristiche nascoste " e non molto utile, ma può essere estremamente interessante in alcuni casi:
Classe sole.varie.Unsafe-ti permetterà di implementare direct memory management 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 si lavora in Swing mi piace il Ctrl nascosto - Maiusc - F1 caratteristica.
Scarica l'albero dei componenti della finestra corrente.
(Supponendo che tu non abbia associato quel tasto a qualcos'altro.)
Ogni file di classe inizia con il valore esadecimale 0xCAFEBABE per identificarlo come bytecode JVM valido.
Il mio voto va a java.util.concurrent con le sue raccolte simultanee e gli esecutori flessibili che consentono tra gli altri pool di thread, attività pianificate e attività coordinate. Il DelayQueue è il mio preferito, dove gli elementi sono resi disponibili dopo un ritardo specificato.
Java.util.Timer e TimerTask possono tranquillamente essere messi a riposo.
Inoltre, non esattamente nascosto ma in un pacchetto diverso dalle altre classi relative a data e ora. Java.util.simultaneo.TimeUnit è utile per la conversione tra nanosecondi, microsecondi, millisecondi e secondi.
Legge molto meglio del solito someValue * 1000 o someValue / 1000.
A livello di linguaassert parola chiave.
Non fa parte del linguaggio Java, ma il disassemblatore javap fornito con JDK di Sun non è ampiamente conosciuto o utilizzato.
L'aggiunta del costrutto for-each loop in 1.5. I
// 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 agli array, dove nasconde la variabile index anziché l'iteratore. Il seguente metodo restituisce la somma dei valori in un array int:
// Returns the sum of the elements of a
int sum(int[] a) {
int result = 0;
for (int i : a)
result += i;
return result;
}
Ho scoperto personalmente java.lang.Void
molto tardi improves migliora la leggibilità del codice in combinazione con i generici, ad esempio Callable<Void>