Después de leer las características ocultas de C #, me pregunté, ¿cuáles son algunas de las características ocultas de Java?
Después de leer las características ocultas de C #, me pregunté, ¿cuáles son algunas de las características ocultas de Java?
Respuestas:
La inicialización de Double Brace me tomó por sorpresa hace unos meses cuando lo descubrí, nunca antes había oído hablar de él.
Los ThreadLocals generalmente no son tan conocidos como una forma de almacenar el estado por hilo.
Dado que JDK 1.5 Java ha tenido herramientas de concurrencia extremadamente bien implementadas y robustas más allá de solo bloqueos, viven en java.util.concurrent y un ejemplo específicamente interesante es el subpaquete java.util.concurrent.atomic que contiene primitivas seguras para subprocesos que implementan la comparación -y-swap y puede correlacionarse con versiones reales de estas operaciones compatibles con hardware nativo.
Unión conjunta en la varianza del parámetro tipo:
public class Baz<T extends Foo & Bar> {}
Por ejemplo, si desea tomar un parámetro que sea Comparable y una Colección:
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);
}
Este método artificial devuelve verdadero si las dos colecciones dadas son iguales o si alguna de ellas contiene el elemento dado, de lo contrario es falso. El punto a tener en cuenta es que puede invocar métodos de Comparable y Collection en los argumentos b1 y b2.
Me sorprendieron los inicializadores de instancia el otro día. Estaba eliminando algunos métodos de código plegado y terminé creando múltiples inicializadores de instancia:
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");
}
}
La ejecución del main
método mostrará:
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
Supongo que esto sería útil si tuviera múltiples constructores y necesitara un código común
También proporcionan azúcar sintáctico para inicializar tus clases:
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 una aplicación llamada VisualVM (bin / jvisualvm.exe) que es una buena GUI además de muchas de las herramientas. Parece más completo que JConsole.
Comodines de Classpath desde Java 6.
java -classpath ./lib/* so.Main
En vez de
java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main
Ver http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html
Para la mayoría de las personas que entrevisto para puestos de desarrollador de Java, los bloques etiquetados son muy sorprendentes. Aquí hay un ejemplo:
// 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;
}
}
}
}
¿Quién dijo que goto
en java es solo una palabra clave? :)
¿Qué hay de los tipos de retorno covariantes que han estado vigentes desde JDK 1.5? Está muy poco publicitado, ya que es una adición poco atractiva, pero, según tengo entendido, es absolutamente necesario para que funcionen los genéricos.
Esencialmente, el compilador ahora permite que una subclase limite el tipo de retorno de un método anulado para que sea una subclase del tipo de retorno del método original. Entonces esto está permitido:
class Souper {
Collection<String> values() {
...
}
}
class ThreadSafeSortedSub extends Souper {
@Override
ConcurrentSkipListSet<String> values() {
...
}
}
Puede llamar al values
método de la subclase y obtener un subproceso ordenado a salvo Set
de String
s sin tener que bajar la conversión al ConcurrentSkipListSet
.
La transferencia de control en un bloque finalmente descarta cualquier excepción. El siguiente código no arroja RuntimeException, se pierde.
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;
}
}
De http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
No he visto a nadie mencionar la instancia de implementación de tal manera que no sea necesario verificar nulo.
En vez de:
if( null != aObject && aObject instanceof String )
{
...
}
Solo usa:
if( aObject instanceof String )
{
...
}
free
de delete
ingresar en C / C ++. Un concepto tan fundamental.
Permitir métodos y constructores en enumeraciones me sorprendió. Por ejemplo:
enum Cats {
FELIX(2), SHEEBA(3), RUFUS(7);
private int mAge;
Cats(int age) {
mAge = age;
}
public int getAge() {
return mAge;
}
}
Incluso puede tener un "cuerpo de clase específico constante" que permite que un valor enum específico anule los métodos.
Más documentación aquí .
mAge
debe ser final. Rara vez hay una razón para los tipos no finales en las enumeraciones.
Los parámetros de tipo para métodos genéricos se pueden especificar explícitamente de la siguiente manera:
Collections.<String,Integer>emptyMap()
public static <T> T foo(T t)
. Luego puede hacer llamadas aClass.<Type>foo(t);
return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList()
. También es útil para algunas invocaciones de métodos donde un simple Collections.emptyMap () daría un error de compilación.
Puede usar enumeraciones para implementar una interfaz.
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; }
}
EDITAR: Años después ...
Yo uso esta función aquí
public enum AffinityStrategies implements AffinityStrategy {
Al usar una interfaz, los desarrolladores pueden definir sus propias estrategias. Usando un enum
medio, puedo definir una colección (de cinco) integradas.
A partir de Java 1.5, Java ahora tiene una sintaxis mucho más limpia para escribir funciones de aridad variable. Entonces, en lugar de simplemente pasar una matriz, ahora puede hacer lo siguiente
public void foo(String... bars) {
for (String bar: bars)
System.out.println(bar);
}
bars se convierte automáticamente en una matriz del tipo especificado. No es una gran victoria, pero una victoria no obstante.
Mi favorito: volcar todos los rastros de la pila de hilos a la salida estándar.
windows: CTRL- Breaken su ventana de cmd / consola java
unix: kill -3 PID
Break
tecla.
Un par de personas han publicado sobre inicializadores de instancias, aquí hay un buen uso:
Map map = new HashMap() {{
put("a key", "a value");
put("another key", "another value");
}};
Es una forma rápida de inicializar mapas si solo está haciendo algo rápido y simple.
O usándolo para crear un prototipo de marco de giro rápido:
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 );
Por supuesto que se puede abusar de él:
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");
}
});
}});
}});
}};
Los proxys dinámicos (agregados en 1.3) le permiten definir un nuevo tipo en tiempo de ejecución que se ajusta a una interfaz. Ha sido útil una cantidad sorprendente de veces.
La inicialización final puede posponerse.
Se asegura de que, incluso con un flujo complejo de lógica, siempre se establezcan valores de retorno. Es demasiado fácil perder un caso y volver nulo por accidente. No hace que la devolución sea nula imposible, solo es obvio que es a propósito:
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;
}
Creo que otra característica "pasada por alto" de Java es la propia JVM. Es probablemente la mejor máquina virtual disponible. Y es compatible con muchos idiomas interesantes y útiles (Jython, JRuby, Scala, Groovy). Todos esos idiomas pueden cooperar fácilmente y sin problemas.
Si diseña un nuevo idioma (como en el caso scala), inmediatamente tiene todas las bibliotecas existentes disponibles y, por lo tanto, su idioma es "útil" desde el principio.
Todos esos idiomas hacen uso de las optimizaciones de HotSpot. La VM está muy bien supervisada y puede depurarse.
Puede definir una subclase anónima y llamar directamente a un método incluso si no implementa interfaces.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
start()
) no está realmente definido en la subclase ...
El método asListjava.util.Arrays
permite una buena combinación de varargs, métodos genéricos y autoboxing:
List<Integer> ints = Arrays.asList(1,2,3);
Arrays.asList
tiene la característica inusual que pueda set()
elementos, pero no add()
o remove()
. Por lo tanto, generalmente lo envuelvo en un new ArrayList(...)
o en un Collections.unmodifiableList(...)
, dependiendo de si quiero que la lista sea modificable o no.
Usar esta palabra clave para acceder a los campos / métodos de contener la clase desde una clase interna. En el ejemplo siguiente, más bien artificial, queremos usar el campo sortAscending de la clase contenedor de la clase interna anónima. Usar ContainerClass.this.sortAscending en lugar de this.sortAscending hace el truco.
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
.
No es realmente una característica, sino un truco divertido que descubrí recientemente en alguna página web:
class Example
{
public static void main(String[] args)
{
System.out.println("Hello World!");
http://Phi.Lho.free.fr
System.exit(0);
}
}
es un programa Java válido (aunque genera una advertencia). Si no ves por qué, ¡mira la respuesta de Gregory! ;-) Bueno, el resaltado de sintaxis aquí también da una pista.
Esto no es exactamente "características ocultas" y no es muy útil, pero puede ser extremadamente interesante en algunos casos:
Clase sun.misc.Unsafe - le permitirá implementar la administración directa de memoria en Java (incluso puede escribir código Java auto modificable con esto si intentas mucho):
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);
}
};
}
Cuando se trabaja en oscilación me gusta la escondida Ctrl- Shift- F1función.
Vuelca el árbol de componentes de la ventana actual.
(Suponiendo que no ha vinculado esa pulsación de tecla a otra cosa).
Cada archivo de clase comienza con el valor hexadecimal 0xCAFEBABE para identificarlo como código de bytes JVM válido.
( Explicación )
Mi voto va a java.util.concurrent con sus colecciones concurrentes y ejecutores flexibles que permiten, entre otros, grupos de subprocesos, tareas programadas y tareas coordinadas. El DelayQueue es mi favorito personal, donde los elementos están disponibles después de un retraso específico.
java.util.Timer y TimerTask se pueden poner en reposo de forma segura.
Además, no está exactamente oculto sino en un paquete diferente de las otras clases relacionadas con la fecha y la hora. java.util.concurrent.TimeUnit es útil al convertir entre nanosegundos, microsegundos, milisegundos y segundos.
Se lee mucho mejor que el habitual someValue * 1000 o someValue / 1000.
CountDownLatch
y CyclicBarrier
- por lo útil!
Palabra clave de afirmación a nivel de idioma .
No es realmente parte del lenguaje Java, pero el desensamblador de Java que viene con JDK de Sun no es ampliamente conocido ni utilizado.
La adición de la construcción de bucle for-each en 1.5. Yo <3 lo.
// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
System.out.println(foo.toString());
}
Y se puede usar en instancias anidadas:
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
La construcción para cada también es aplicable a las matrices, donde oculta la variable de índice en lugar del iterador. El siguiente método devuelve la suma de los valores en una matriz 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
aquí es muy confuso, ya que la mayoría de la gente espera que yo sea un índice y no el elemento de matriz.
Descubrí personalmente java.lang.Void
muy tarde: mejora la legibilidad del código junto con los genéricos, p. ej.Callable<Void>