2009-08-09 7 views
18

Una de las cosas que pueden ser un poco molestas acerca de Java es la cantidad de código que necesita para expresar conceptos. Creo en la filosofía de "menos código es mejor", y me gustaría saber cómo puedo escribir Java sin ser tan frustrantemente prolijo. Recientemente, leí la pregunta Hidden Features of Java y fui introducido usando double-brace initialization para simular un literal de Lista o Mapa. Por supuesto, existen inconvenientes en el uso de este método, pero le permite hacer ciertas cosas con un número significativamente menor de caracteres y (si lo formatea correctamente) hacer que el código sea mucho más claro y claro. Me pregunto si no hay otros trucos ingeniosos y características de lenguaje menos conocidas que podrían hacer que mi código sea más conciso.Qué son buenos patrones/técnicas para reducir la verbosidad de Java

Me gustaría ver las respuestas con una explicación de la técnica, la manera más detallada que reemplaza, y los posibles inconvenientes de usar la técnica.

+7

Si Dios no quería que Java para ser prolijo, habría inventado Perl – ChssPly76

+1

para la inicialización de Double Brace, consulte: http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization –

+2

Si Java es la respuesta, debe haber sido una pregunta terriblemente prolija. – Sneakyness

Respuesta

8

A una similar que probablemente ya sabe acerca, a través del "varargs" característica:

String[] array = new String[] {"stack", "over", "flow"}; 
List<String> list = Arrays.asList(array); 

puede abreviarse

List<String> list = Arrays.asList("stack", "over", "flow"); 
Es cierto que no

un ahorro enorme, pero sí reduce el nivel de detalle de una un poco. Como señala Thomas, la lista será inmutable, así que ten cuidado con eso. En realidad, puede modificar la lista, simplemente no puede cambiar su longitud. Gracias a pimlottc por señalar eso.

+0

¡Sí! He usado varargs en mis propias funciones, pero por alguna razón he pasado por alto el hecho de que Arrays.asList usa varargs. ¡Gracias! –

+1

Pero cuidado, la lista será inmutable. –

+1

Eso no es cierto, la lista es mutable; simplemente no puedes cambiar su longitud. Puede reemplazar cualquier valor dentro de la lista, p. Arrays.asList ("1", "2", "3"). Set (0, "a") es válido. – pimlottc

9

Antes de la introducción del diamond operator en Java 7, los métodos de fábrica estáticos para crear tipos genéricos podrían usarse para reducir la verbosidad al reducir la necesidad de repetir el parámetro de tipo. (Esto es porque sin el operador de diamantes, Java nunca se infiere el parámetro de tipo de constructores, pero lo hará en los métodos de llamadas.) Google Collections utiliza esta técnica, por lo que puede escribir:

Set<MyClassWithALongName> set = Sets.newHashSet(); 

en lugar de:

Set<MyClassWithALongName> set = new HashSet<MyClassWithALongName>(); 

Busque en las clases Lists, Sets y Maps de Google Collections para los métodos que comienzan con "nuevo" para obtener más ejemplos de esto.

A menos que esté escribiendo para una versión anterior de Java, a partir de Java 7 es mejor usar el operador de diamante.

+0

¡Asegúrese de utilizar sus propios métodos si aún no está utilizando Google Collections! Estoy seguro de que Laurence no quiso decir lo contrario :) – Philip

+1

Obsoleto desde Java 7. Ver operador de diamantes. – user2418306

+0

@ user2418306 Estás en lo correcto. He actualizado la respuesta. ¡Gracias! –

0

inicializadores estáticos

Ejemplo 1 (mapa):

Map<String, String> myMap = new HashMap<String, String>() {{ 
    put ("a", "b"); 
    put ("c", "d"); 
}}; 

Ejemplo 2 (Lista):

List<String> myList = new ArrayList<String>() {{ 
    add("a"); 
    add("b"); 
    add("c"); 
}}; 
+2

No me gusta el hecho de que esto crea una clase anónima. –

+2

¿Por qué no te gustan las clases anónimas Ravi? Una de las desventajas que conozco sobre esta técnica es que si utiliza el mapa o la lista resultante fuera de su objeto adjunto, está pasando una referencia implícita al objeto que lo contiene. Esto puede causar pérdidas de memoria. Pero mientras lo entiendas y tengas cuidado, no veo el problema. Tal vez esta advertencia debe agregarse a la respuesta como un inconveniente. –

+0

Sí, esto es menos detallado, pero los miembros más jóvenes de tu equipo podrían confundirse. Además, proporciona una advertencia del compilador. –

2

Fluent interfaces pueden ayudar - con ayuda de los constructores y método de encadenamiento de hacer algo parecido a una DSL en java. El código con el que termina puede ser un poco más difícil de leer, ya que rompe las convenciones de codificación normales de Java, como eliminar el conjunto/obtener de las propiedades.

Así en una interfaz fluida falsa oscilación es posible definir un botón así:

JButton button = Factory.button().icon(anIcon).tooltip("Wow").swing(); 

Otro enfoque es utilizar otro idioma hay muchos que se integra bien con la JVM, tales como:

+0

¿Tiene un ejemplo de una API Java que proporciona una interfaz fluida? Estoy familiarizado con el concepto de RoR y también he mirado a FluentNHibernate, pero me gustaría ver cómo se siente esto en el mundo de Java. De todos modos, +1 por mencionar a Scala. Un lenguaje agradable que se integra excelentemente con Java y JVM. Todavía tengo que probarlo en un proyecto real. –

+0

Quizás quieras 'Hamcrest'? Eche un vistazo a los ejemplos [aquí] (https://code.google.com/p/hamcrest/wiki/Tutorial) y [aquí] (http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest /Matchers.html) –

+0

Usar otro idioma es evitar, no reducir, la verbosidad de java. – user2418306

8

Utilice un marco de inyección de dependencia como la primavera. Casi siempre estoy sorprendido de cómo se produce mucho lógica de construcción de código.

+1

También prueba Guice. http://code.google.com/p/google-guice/ Produce configuraciones más cortas que Spring (especialmente en comparación con las configuraciones XML de Spring) y obtienes comprobación de tipos en tiempo de compilación. –

+0

Bueno, yo soy todo para la configuración de primavera basada en anotaciones, con 5 líneas de xml y sin código. – krosenvold

+0

La metaprogramación sería un nombre más genérico para esta técnica. El Proyecto Lombok es otro ejemplo de este enfoque. – user2418306

2

Un método "closeQuietly" se puede utilizar en bloques try/finally en situaciones donde las excepciones IO al cerrar son poco interesantes (o imposibles).

Closeable c = null; 
try { 
    ... 
    c = openIt(...); 
    ... 
} finally { 
    closeQuietly(c); 
} 

donde:

/** Close 'c' if it is not null, squashing IOExceptions */ 
public void closeQuietly(Closeable c) { 
    if (c != null) { 
     try { 
      c.close(); 
     } catch (IOException ex) { 
      // log error 
     } 
    } 
} 

Tenga en cuenta que con Java 7 y versiones posteriores, el nuevo "intento con recursos" sintaxis hace que este ejemplo particular redundante.

+0

Obsoleto desde Java 7. Consulte try with resources. – user2418306

3

He descubierto que la forma más efectiva (¿única?) De escribir conciso java es no escribir java en absoluto. En los casos en que necesitaba escribir algo rápidamente que todavía funciona con Java, he descubierto que Groovy es una excelente opción. El uso de un lenguaje más conciso que aún compila en bytecode JVM puede ser una excelente solución. Si bien no tengo experiencias personales con él, he escuchado que Scala es una opción aún mejor que Groovy en muchos casos.

+2

Groovy es lento como el infierno en comparación con las alternativas. –

3

Echa un vistazo lambdaj. Tiene muchas características que pueden ayudarlo a hacer que su código sea más conciso y legible.

+0

Esta respuesta es demasiado amplia.Por favor, brinde un ejemplo de código detallado y contraparte concisa. Si alude a la notación lambda para cierres, entonces esto es obsoleto desde Java 8. – user2418306

1

me encontré con un post dando una técnica interesante que permite escribir un mapa literal en Java como si sería capaz de hacerlo en Perl, Python, Ruby, etc: Building your own literals in Java - Tuples and Maps Me gusta mucho este enfoque! Lo resumiré aquí.

La idea básica es crear una clase de par genérica y definir funciones estáticas que construirán un par, y un mapa de una matriz de pares varargs. Esto permite que el siguiente mapa concisa definición literal:

Map(o("height", 3), o("width", 15), o("weight", 27)); 

Dónde o es el nombre de la función estática para construir un par de objetos T1 y T2, para cualquier tipo de objeto T1 y T2, y Map es el nombre de la función estática para construir un Mapa. No estoy seguro de que me guste la elección de Map como el nombre de la función de construcción del mapa porque es lo mismo que el nombre de la interfaz de Java, pero el concepto sigue siendo bueno.

0

Más Guave bondad para inicializar mapas inmutables (que me está resultando ser un caso más común forma de inicializar mapas mutables): el ImmutableMap.of(...) variants

Map<Service, Long> timeouts = ImmutableMap.of(
    orderService, 1500, 
    itemService, 500); 
0

vez tiene que recorrer una colección, sólo para mapear sus elementos por una de sus propiedades?No más, gracias a Maps.uniqueIndex():

private void process(List<Module> modules) { 

    Map<String, Module> byName = Maps.uniqueIndex(modules, new Function<Module, String>() { 
      @Override public String apply(Module input) { 
       return input.getName(); 
      } 
     }); 

o si esto es lo suficientemente frecuentes, que la función de un miembro de public static finalModule modo que lo anterior se reduce a:

Map<String, Module> byName = Maps.uniqueIndex(modules, Module.KEY_FUNCTION); 
+0

Obsoleto desde Java 8. Consulte la referencia del método. – user2418306

Cuestiones relacionadas