Final vs Inmutable vs constante

CONSTANTE

public static final String VAR =  "var";

Esta es la declaración mas común de una constante.

  • Public, para que se pueda acceder desde cualquier clase, sin tener que instanciar dicha clase.
  • Static para que sea común a todas las clases que hereden de esta clase.
  • Final para expecificar que una vez que sea instanciada no puede modificarse.
  • El tipo de dato que va a representar.
  • La inicialización de la constante.

FINAL

private final String var;

Podemos declararla privada, sino queremos que sea para todo el mundo.
El indicado final, señala que una vez inicializada no se podra modificar.
NOTA: si es un tipo de dato privitivo (int, long, etc.) impedira que se modifique su valor.
Pero si es una referencia, solo impide que se modifique la referencia, no el valor de la referencia.
No se puede heredar si es final.

INMUTABLE

Inmutable significa que el valor no cambia.

private String var = "perro";
private String var = "gato";

Para generar la primera linea, se crea un objeto con el contenido “perro”, este contenido
no puede ser cambiado o modificado, ya que es inmutable. Se le pasa una referencia a la
variable declarada.
En la segunda linea se genera un objeto con el contenido “gato”, inmutable (no se puede cambiar),
y se le pasa una referencia al la variable var de este objeto.
Es decir el objeto var no ha cambiado su valor, ha cambiado la referencia.

Diferencia entre final, finally y finalize()

Si tienes que liberar un fichero gestionado por un objeto, ¿que harías, llamar al método finalize(), o introducir una clausula finally?
  • final: decalaración de una constante.
  • El método finalize(): Algunos lenguajes de programación orientados a objetos requieren que el programador destruya explícitamente los objetos cuando dejan de utilizarse. Sin embargo en java, la JVM se responsabiliza de reclamar la memoria reservada por los diferentes objetos estos quedan fuera de alcance (proceso denominado “garbage collection“, o de limpieza), por lo que se libera al programador de esta tarea. Hay dos importantes características del proceso de limpieza: 1) cuando un object sale de alcance, inmediatamente se le considero que pertenece a la “colección basura”. Pero no es del todo preciso. Al salir de alcance, lo que ocurre es que se le marca como candidato para la “colección basura”, y el proceso limpieza (que gestiona la colección) periódicamente va reclamando estos objetos en memoria fuera de alcance sin referenciar, de modo recursivo. Lo malo es que esto no ocurre en momentos predeterminados, pues no existe una especificación exacta en la JVM de cuando se ejecutará el proceso de limpieza.
    Si el proceso se ejecuta antes de que un objeto haya pasado a la colección-de-basura, el runtime de java invoca al método finalize() del objeto, permitiendo que este pueda realizar cualquiera las operaciones que liberen los recursos demandados al sistema tales como ficheros o sockets abiertos. Este método finalize() se declara como: protected void finalize() throws Throwable. El proceso de limpieza se ejecuta como un hilo demonio de bajo-nivel y, en general, para este tipo de hilos, no es esencial que el hilo se complete antes de que la aplicación termine.
    He aquí el problema, pues aunque pueda utilizarse el método finalize para realizar las operaciones de limpieza, el hilo recolector encargado de llamar al método finalize() de los objetos podría ejecutarse de un modo impredecible.
  • La declaración finally en un bloque de código implica la liberación explícita de cualquiera de los recursos externos que puedan ser mantenidos. A diferencia del método finalize(), la declaración finally no depende del proceso de limpieza del recolector de basura. La liberación de recursos dentro de un bloque finally es más aconsejable pues se garantiza que el código dentro del finally siempre será ejecutado incluso cuando haya una excepción inesperada en tiempo de ejecución.

Clases y métodos genéricos

Clases genéricas

public class UseTwo<T, X> {
	T one;
	X two;

	UseTwo(T one, X two) {
		this.one = one;
		this.two = two;
	}

	T getT() {
		return one;
	}

	X getX() {
		return two;
	}

	// test it by creating it with <String, Integer>
	public static void main(String[] args) {
		UseTwo<String, Integer> twos = new UseTwo<String, Integer>("foo", 42);
		String theT = twos.getT(); // returns a String
		int theX = twos.getX(); // returns Integer, unboxes to int
	}
}

Métodos genéricos:

public class CreateAnArrayList {
	public <T> void makeArrayList(T t) { // take an object of an unknown type and use a
	                                     // "T" to represent the type
		List<T> list = new ArrayList<T>(); // now we can create the
		// list using "T"
		list.add(t);

		System.out.println(list.get(0).toString());
	}

	public static void main(String[] args) {
		CreateAnArrayList arr = new CreateAnArrayList();
		Horse h = new Horse(4, "eno");
		arr.makeArrayList(h);
	}
}

‘Collection’ en java 1.6

List: un conjunto de cosas
Set: cosas únicas
Map: cosas con un único ID (identificador)
Queues: cosas organizadas en orden a cómo deben ser procesadas.

Ordenado (Ordered): Significa que la colección se puede iterar en un orden específico no aleatorio.

Clasificado (Sorted): el orden de la colección es determinado acorde a unas reglas, basadas en las propiedades de los objetos que la componen. La ordenación natural: alfabética o numérica.

Comparable vs Comparator (artículo)

A través de la Interfaz ‘Comparable’ que define como la instancia de una clase puede ser comparada con otra (la clase persona se ordena por el nombre).

java.lang.Comparable
java.util.Comparator
int objOne.compareTo(objTwo)
int compare(objOne, objTwo)
Returns
negative if objOne < objTwo
zero if objOne == objTwo
positive if objOne > objTwo
Same as Comparable
You must modify the class whose instances you want to sort. You build a class separate from the class whose instances you want to sort.
Only one sort sequence can be created
Many sort sequences can be created
Implemented frequently in the API by:

String, Wrapper classes, Date, Calendar...
Meant to be implemented to sort instances of third-party classes.
public class Employee implements Comparable<Employee>
{
private String name;
private int age;

public Employee(String name, int age)
{
this.name = name;
this.age = age;
}

public int compareTo(Employee e)
{
//comparison strategy
}

public static void main(String[] args)
{
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add( new Employee("Tim", 10) );
employeeList.add( new Employee("Rolvin", 11) );
employeeList.add( new Employee("Gerald", 12) );

Collections.sort(employeeList);
}
}

A través de la interfaz ‘Comparator’: se pueden implementar otras clases que implementan otros tipos de ordenación (la clase persona se ordena por nombre, o por apellido o por edad).

public class SortByName implements Comparator<Employee>
{
public int compare(Employee e1, Employee e2)
{
//comparison strategy here
}
}
public class SortByAge implements Comparator<Employee>
{
public int compare(Employee e1, Employee e2)
{
//comparison strategy here
}
}
public static void main(String[] args)
{
List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add( new Employee("Tim", 10) );
employeeList.add( new Employee("Rolvin", 11) );
employeeList.add( new Employee("Gerald", 12) );

Collections.sort(employeeList, new SortByName() );//sort by name;
Collections.sort(employeeList, new SortByAge() );//sort by age;

}

La interfaz List

Sus implementaciones son ordenadas por el index.

get(int index), indexOf(Object o), add(int index, Object obj)

ArrayList: es un array con la capacidad de crecer. Ofrece una rápida iteración y acceso. Ordered pero no Sorted.
Vector: lo mismo que ArrayList pero es Synchronized.
LinkedList: mantiene el orden de los objetos según su inserción. Más lento en la iteración que el ArrayList pero más rápido en la inserción y eliminación. Implementa la interfaz java.util.Queue, que proporciona los métodos:

java.util.Queue
peek(), poll(), and offer().

El método peek devuelve, pero no borra, la cabecera de la cola.
El método poll devuelve y borra la cabecera de la cola
El método add inserta un elemento a no ser que se supere la capacidad de la cola, en este caso se lanza una IllegalStateException.
El método offer es igual que add pero devuelve false si existe algun error en la insercción.

La interfaz Set

No permite duplicados.
HashSet: es ‘unsorted and unordered’ no se puede ni ordenar ni clasificar. Usa el hasCode() de los objetos para insertarlos. Para colecciones sin duplicados pero no importa el orden en que se recorran
LinkedHashSet: es una versión ordenada de HashSet. Ordena los elementos en función del orden de inserción.
TreeSet: usa la estructura de árbol Red-Black. Ordena los elementos según se insertan en orden ascendente. Implementa ‘NavigableSet’. Puedes personalizar la clasificación.

La interfaz Map

Tiene un único identificador para un valor. (key /value)
HashMap: es ‘unsorted and unordered’ no se puede ni ordenar ni clasificar. Permite la llave nula y múltiples valores nulos.
HashTable: similar a HashMap pero es Synchronized. Ningún elemento debe ser nulo. LinkedHashmap: mantiene el orden de inserción. TreeMap: Ordena los elementos según se insertan en orden ascendente. Implementa ‘NavigableSet’. Puedes personalizar la clasificación.

La interfaz Queue

Como una pila FIFO (First In – First Out).
PriorityQueue: es una lista de prioridades (Priority In – Priority Out). La prioridad viene determinada por la clasificación de los elementos.

CLASE
MAP
SET
LIST
ORDERED
SORTED
HashMap
X
 
 
NO
NO
HashTable
X
 
 
NO
NO
TreeMap
X
 
 
SORTED
By natural order or custom comparison rules
LinkedHashMap
X
 
 
By insertion order or last access order
NO
HashSet
 
X
 
NO
NO
TreeSet
 
X
 
SORTED
By natural order or

custom comparison rules
LinkedHashSet
 
X
 
By insertion order
NO
ArrayList
 
 
X
BY INDEX
NO
Vecctor
 
 
X
BY INDEX
NO
LinkedList
 
 
X
BY INDEX
NO
PriorityQueue
 
 
 
SORTED
By TO-DO order

ArrayList

Ventaja sobre un array: a) crece dinámicamente, b)inserción y búsqueda mejoradas.
Cómo ordenar un ArrayList:

ArrayList<String> stuff = new ArrayList<String>();
stuff.add("Denver");
stuff.add("Boulder");
stuff.add("Vail");
stuff.add("Aspen");
stuff.add("Telluride");
System.out.println("unsorted " + stuff);
Collections.sort(stuff);
System.out.println("sorted " + stuff);
unsorted [Denver, Boulder, Vail, Aspen, Telluride]
sorted [Aspen, Boulder, Denver, Telluride, Vail]

Utilizando la ordenación de los arrays.

Arrays.sort(arrayToSort)

Búsqueda en Arrays y Collection:
-   Utilizan el método BinarySearch(): Arrays.binarySearch(arrayList,”one”)
-   Las búsquedas satisfactorias devuelven un ‘int’ que representa el índice del elemento.
-   Las búsquedas no satisfactorias devuelven in ‘int’ que representa el punto de insercción.

Convertir Arrays en Listas

String[] sa = {"one", "two", "three", "four"};
List sList = Arrays.asList(sa);

Backed Collections

TreeMap<String, String> map = new TreeMap<String, String>();
map.put("a", "ant"); map.put("d", "dog"); map.put("h", "horse");
SortedMap<String, String> submap;
submap = map.subMap("b", "g"); // #1 create a backed collection
System.out.println(map + " " + submap); // #2 show contents
map.put("b", "bat"); // #3 add to original
submap.put("f", "fish"); // #4 add to copy
map.put("r", "raccoon"); // #5 add to original - out of range
// submap.put("p", "pig"); // #6 add to copy - out of range
System.out.println(map + " " + submap); // #7 show final contents
{a=ant, d=dog, h=horse} {d=dog}
{a=ant, b=bat, d=dog, f=fish, h=horse, r=raccoon} {b=bat, d=dog, f=fish}

TreeMap.subMap(desde el valor inicial, hasta el valor final);
La subcoleción registra las modificaciones realizadas en la colección a la que pertenece.
El dato insertado en la subcoleción también se registra en la colección.

headSet: Empieza al principio y termina en el dato pasado como parámetro.
TreeSet.headSet();                        TreeMap.headSet();

subSet: Indica cuando empieza y acaba con los parámetros.
TreeSet.subSet();                           TreeMap.subSet();

TailSet: desde el parámetro pasado como argumento hasta el final.
TreeSet.tailSet();                            TreeMap.tailSet();

Bibliografia:
- http://java.sun.com/docs/books/tutorial/collections/interfaces/index.html
- Libro:  SCJP Sun Certified Programmer for Java 6 Exam 310-065

Sobrecargando Widening, Boxing, Varargs

Widening

Las 19 siguientes conversiones de tipos primitivos son llamados ‘widening primitive conversions’:

byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double

No pierden información

class Test {
   public static void main(String[] args) {
      int big = 1234567890;
      float approx = big;
      System.out.println(big - (int)approx);
   }
}

Consola:

-46

Indica la información que se ha perdido durante la conversión de tipos, pero porque el tipo float no es preciso con 9 digitos.

Narrowing

Las 23 siguientes conversiones de tipos primitivos son llamados ‘narrowing primitive conversions’:

byte to char
short to byte or char
char to byte or short
int to byte, short, or char
long to byte, short, char, or int
float to byte, short, char, int, or long
double to byte, short, char, int, long, or float

Se pierde valor o precision.

Autoboxing

Para insertar un int en una colección, lo que se hace automaticamente es:

1.- BOX guardar la variable en una clase que la envuelva(wrapper), en este caso Integer.
2.- se guarda en la collection.
3.- cuando quieras recoger el dato se hace UNBOX del Integer usando intValue(), te devuelve en int.

Varargs

Hay veces que necesitas enviar a un metodo, muchas instancias de un mismo objeto. Pero en tiempo de compilacion no sabes cuantas. En vez de enviar un array o una collection, puedes usar: ‘variable arity parameters’ ó como se les conoce formalmente: ‘varargs‘.

class VarGreeter {
   public static void printGreeting(String... names) {
      for (String n : names) {
        System.out.println("Hello " + n + ". ");
      }
   }

   public static void main(String[] args) {
      printGreeting("Paul", "Sue");
   }
}

Sobrecargando Widening, Boxing, Varargs

W -> B -> V
(WB: NO)
(BW: SI)
(VW, VB: SI)

1. Widening wins over boxing and Varargs
2. Boxing wins over Varargs
3. Widening of reference variable depends on inheritance(so, Integer cannot be widened to Long. But, Integer widened to Number).
4. Widen and boxing is not possible
5. Boxing and widening is possible
6. Varargs can be combined with either boxing or widening

POO Overriding(Sobreescritura) vs Overloading(sobrecarga)

Del libro: SCJP Sun Certified Programmer for Java 6 Exam 310-065

Métodos Sobrecargados (Overloaded)

Métodos Sobrescritos (Overridden)

Argumento(s)

Debe cambiar

No debe cambiar

Tipo devuelto
(Return type)

No cambiar.

No cambiar excepto para ‘covariant returns’.

Excepciones

No cambiar.

Se puede reducer o eliminar

No se debe lanzar una nueva excepción o ampliar la existente.

Acceso

No cambiar

Se puede hacer más restrictiva

Invocación

El tipo de referencia determina que versión de sobrecarga (basada en los tipos de argumentos declarados) ha sido seleccionada. Ocurre en tiempo de compilación. El método invocado todavía es una invocación virtual del método, en tiempo de ejecución, pero el compilador sabe la firma del método que es invocado. Así, en tiempo de ejecución, el argumento emparejado ya se habrá llevado a cabo, no solo en la clase en la que el método reside

El tipo de objeto (el tipo de la instancia actual en la Heap) determina que método es seleccionado. Sucede en tiempo de ejecución.

Reglas a seguir para sobrescribir un método:
- La lista de argumentos debe coincidir con el método sobrescrito.
- El tipo devuelto debe ser el mismo, o un subtipo de.
- El acceso no puede ser más restrictivo que el método sobrescrito.
- El acceso puede ser menos restrictivo que el método sobrescrito.
- Las instancias de los métodos puede ser sobrescritos solamente si son herederos de la subclase.
- El método sobrescrito puede lanzar cualquier excepción ‘uncheked’ en tiempo de ejecución.
- El método sobrescrito no debe lanzar excepciones ‘checked’ que son nuevas o mas amplias que las declaradas.
- El método sobrescrito puede lanzar excepciones limitadas o menos excepciones.
- No sobrescribir métodos ‘final’.
- No sobrescribir métodos ‘static’.
- Si un método no puede ser heredado, no se puede sobrescribir.
Los métodos sobrecargados:
- Deben cambiar la lista de argumentos.
- Pueden cambiar el tipo devuelto.
- Pueden cambiar los modificadores de acceso.
- Pueden declarar nuevas excepciones o ampliar las existentes.
- Un método puede ser sobreescrito en la misma clase o en una subclase

Un ejemplo:


package com.codingdojo.pomodoro;
public class Animal {
protected static int cont = 0;
protected int patas;
protected String comida;
protected String sonido;

public Animal(int patas, String sonido) {
this.patas = patas;
this.sonido = sonido;
++cont;
}

public void come(String comida) {
this.comida = comida;
}

public int getCont() {
return cont;
}

public String toString() {
return "Un " + getClass().getName() + " come: " + comida + ", "+ "tiene " + patas + " patas" + ", " + "y " + sonido;
}
}

package com.codingdojo.pomodoro;
public class Horse extends Animal {
public Horse(int patas, String sonido) {
super(patas, sonido);
}

// sobrecarga(overload) de operadores
public void come(String apple, String eno, String salt) {
comida = apple + ", " + eno + ", " + salt;
}
}

package com.codingdojo.pomodoro;
public class Dog extends Animal {
public Dog(int patas, String sonido) {
super(patas, sonido);
}

}

package com.codingdojo.pomodoro;
public class Cat extends Animal {
public Cat(int patas, String sonido) {
super(patas, sonido);
}

// sobreescritura(overridding) de operadores
public void come(String leche) {
comida = "un poco de: " + leche;
}

}

package com.codingdojo.pomodoro;
import java.util.ArrayList;
import java.util.List;

public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Animal(0, "--");
Horse horse = new Horse(4, "relincha");
Dog dog = new Dog(4, "ladra");
Cat cat = new Cat(4, "maulla");

List<Animal> list = new ArrayList<Animal>();
list.add(animal);
list.add(horse);
list.add(cat);
list.add(dog);

for (Animal animalito : list) {
if (animalito instanceof Horse) {
((Horse) animalito).come("manzanas", "eno", "sal");
}else if (animalito instanceof Dog) {
((Dog) animalito).come("pienso");
}else if (animalito instanceof Cat) {
((Cat) animalito).come("Leche");
}else {
animalito.come("lo que puede");
}

System.out.println(animalito.toString());
}

System.out.println("Numero de instacias de Animal: "+animal.getCont());
}
}

Salida de consola:

Un com.codingdojo.pomodoro.Animal come: lo que puede, tiene 0 patas, y --
Un com.codingdojo.pomodoro.Horse come: manzanas, eno, sal, tiene 4 patas, y relincha
Un com.codingdojo.pomodoro.Cat come: un poco de: Leche, tiene 4 patas, y maulla
Un com.codingdojo.pomodoro.Dog come: pienso, tiene 4 patas, y ladra
Numero de instacias de Animal: 4

Diferencias entre STACK y HEAP de la JVM

STACK HEAP
Almacena Variables locales Objetos (clases, métodos, instancias)
Nunca se puede manipular directamente Se puede redimensionar y tiene el ‘Garbage Collector’
Tiene acceso al procesador, ‘stack pointer’

no

La memoria no necesita ser contigua Idem
Cada hilo tiene un stack Común a toda la JVM
OutOfMemory No tiene espacio para un nuevo hilo. Necesita más tamaño.
StackOverflow Requiere más espacio del permitido

·

Ejemplo:

var blue
var red
ref 0×456783= (Heap reference)
var tom
ref 0×498702= (Heap reference)
var diane
Heap (0×4567= 83)
name = Susan
age = 26
city= London
height= 5’7
sex= female

Heap (0×4987= 02)
name= Paul
age= 21
city = Glasgow
height = 6’0
sex = male

Ejemplo grafico

Bibliografia:
- http://wiki.answers.com/Q/What_is_difference_between_heap_memory_and_stack_memory
- http://www.sap-img.com/java/difference-between-stack-and-heap.htm
- http://www.soygeek.com/index.php/2008/02/12/almacenamiento-en-java/
- http://net.pku.edu.cn/~course/cs101/2008/resource/heapAndStack.html

¿Qué es Rake?

Del diccionario inglés:
-nombre: rastrillo, calavera.
-verbo: examinar, registrar por.
El otro día publiqué una traducción de un artículo de Kent R. Spillner sobre herramientas de contrucción (builds). Elogiaba vehementemente una herramienta: Rake.
Voy a intentar satisfacer mi curiosidad. Sobre todo: ¿es compatible con proyectos java? ¿puedo cambiar mi ‘build‘ de Maven por uno de Rake?.
Rake esta hecho con Ruby [Ruby es un lenguaje de programación interpretado, reflexivo y orientado a objetos. Combina una sintáxis inspirada en Python, Perl con características de programación orientada a objetos similares a Smalltalk. Comparte también funcionalidad con otros lenguajes de programación como Lisp, Lua, Dylan y CLU. Ruby es un lenguaje de programación interpretado en una sola pasada y su implementación oficial es distribuida bajo una licencia de software libre].
Rake tiene las siguientes caracteristicas:
- los ficheros Rake, reakefiles, idénticos a los ‘makefiles‘ estan completamente definidos en la sintáxis de Ruby. No hay que editar ficheros XML. Los Makefile no tiene una sintáxis rara sobre la que preocuparse (¿es un tabulado o un espacio?).
- Los usuarios pueden especificar tareas con prerequisitos.
- Rake soporta patrones de regla para sintetizar tareas implícitas.
- Listas de ficheros flexibles que trabajan como arrays, pero saben como manipular ficheros y rutas.
- Una libreria de tareas pre-empaquetadas para crear fácilmente construcciones rakefiles.
Documentación oficial
Herramientas para Java, basadas en Rake: buildr, Raven.

Herramientas de construccion de Java: ANT vs Maven

ACTUALIZACIÓN: Llegué a este artículo a través de un tweet de Kent Beek. Leelo bajo tu responsabilidad y lee los comentarios.
La mejor herramienta es la que has escrito tú. Cada proceso de construcción de un proyecto es único y a menudo los proyectos individuales necesitan ser construidos de diferentes maneras. Para los autores de estas herramientas es imposible anticiparse a cada requerimiento de construcción y temerario intentarlo (desarrolladores de Apache: tomad nota). Lo mejor que puede hacer cualquier herramienta es, proveer una libreria  flexible de tareas reutilizables, que se pueden adaptar fácilmente a tus necesidades, pero es insuficiente. Extraoficialmente las tareas nunca se adaptan a tu proyecto perfectamente. Perderás incontables horas luchando para hacer que estas tareas hagan lo que necesitas exactamente, solamente para darte por vencido y escribir un plugin en su lugar. Es rápido y fácil escribir tu propia herramienta de construcción personalizada, requiere menos mantenimiento del que temes. No te preocupes: las construcciones deberían ajustarse a tu proyecto, no al revés.
Si no quieres escribir tu propia herramienta, puedes usar Rake. Rake es la mejor herramienta de construcción para proyectos java. Proporciona un montón de métodos estándar para desarrollar las tareas de construcción más comunes, y cualquier cosa puede ser implementada rápidamente en Ruby. La gran ventaja de Rake sobre otras herramientas es que puede escribir scripts en un lenguaje de programacion real. Tiene otras ventajas, pero no son tan importantes.
De esta manera puedes escribir y personalizar herramientas de construcción para tus proyectos. Si no quieres puedes usar Rake. Si no quieres cambiar, deberías. Si la política impulsa las decisiones tecnológicas, si nunca te permitirán cambiar, entonces quedate en tu trabajo o deja el proyecto.
Si te falta coraje, entonces usa Ant. Ant es la segunda mejor herramienta de construcción existente para proyectos java. Es inferior a Rake, Ant sigue siendo una gran herramienta de construcción. Es maduro y estable, es rápido y viene con una rica librería de tareas. Hace posible script ricos (pero no todo es fácil), complejos procesos de construcción adaptados a las necesidades de tu proyecto.
Puedes escribir tu propia herramienta de construcción o cambiar a Rake, o pelear por cambiar a Rake, o irte a algún lugar donde puedas usar Rake. Y si todo esto falla, usa Ant hasta que puedas encontrar un nuevo trabajo donde se use Rake.
¡Eso es!, estas son las únicas que puedo recomendar, porque nunca, nunca, ¡bajo ninguna circunstancia uses Maven!.
Las construciones de Maven son una desesperacion infinita que lentamente te arrastrara al más profundo pozo de oscuridad del infierno (donde Maven fue forjada). Inicialmente tardaras 10 minutos en instalar y arrancar Maven, podrás ser feliz con él durante algún tiempo. Pero a medida que el proyecto evoluciona, y tu configuración de contruccion crece, el elemental pom.xml que iniciaste resultará inadecuado. Lentamente añadirás más configuraciones para trabajar con lo que necesitas, pero hay mucho que puedes configurar… (traductor: sigue hablando mal de Maven).
En serio, Maven es una implementación horrible de malas ideas. Creo que alguien en alguna lugar tenía (quizás todavia tiene) una visión de Maven que era razonable, sino seductora. Pero la actual implementación de Maven carece de cualquier vestigio de dicha vision. De hecho cada cosa en Maven está tan mal, que se sirve de ejemplos de como no hacer software.  Piensas que tu construcción es alucinante cuando funciona al revés que Maven.
Tenga en cuenta la salida de resultados de pruebas del plug-in Surefire de Maven. Todo parece bien cuando las pruebas se estan pasando, pero los informes de Surefire son una pesadilla para depurar cuando las cosas van mal. La única información conectada a la consola es el nombre del test que ha caído. Manualmente tienes que hacer una referencia cruzada con el nombre que se ha grabado en el fichero log, que se encuentra en el directorio target/surefire-reports, ¡pero estos logs estan escritos uno por test!, así que si fallan múltiples test, deberás separar múltiples ficheros logs. Parece una cosa menor, pero rápidamente será una molestia y hundirá la producción.
Los defensores de Maven reclaman que la herramienta cumple el Principio de la Convención sobre Configuración. Mienten. La única convención que soporta Maven es: compilar, ejecutar test unitarios, paquetes .jar. Usar Maven para hacerlo todo requiere configurar las convenciones. ¿Quieres empaquetar un fichero .war?, configúralo. ¿Quieres ejecutar tu aplicación desde la línea de comandos?, configúralo. ¿Quieres ejecutar test de aceptación o test funcionales o desarrollar test con tu ‘build’?, configúralo, esto implica no ejecutar los test unitarios, o no ejecutarlos mientras dura la fase convencional de test unitarios del proceso ‘build‘.  ¿Quieres generar un indicador del estado del código para tu proyecto? configúralo, pero los test se ejecutarán dos veces (o solamente una, pero no durante la ejecución normal de los test) y a veces informará de un estado de código de 0% a pesar del completo juego de test.
Hablando de confguración, Maven tiene la peor sintaxis de configuración desde Sendmail: alternando la forma normal XML. Como consecuencia, la configuración de Maven es abundante, difícil de leer y de escribir. Las cosas que puedes hacer en una o dos líneas de Ruby o XML con Rake o Ant requieren seis, siete u ocho líneas en la configuración del pom.xml (asumiendo que es posible hacerlo en Maven).
No hay nada coherente en la configuración de Maven. Algunas cosas son configuradas como ‘classpath references‘ (una referencia desde la ruta donde se encuentra la clase) hacia los ficheros ‘.properties’ construidos en ficheros ‘.jar‘ configurados como dependencias, algunas son configuradas como rutas absolutas o relativas de los ficheros en el disco y algunas son configuradas como propiedades del sistema en la JVM cuando se ejecuta Maven. Y algunas de estas rutas relativas son portadas a través de los proyectos porque Maven conoce como resolverlas correctamente, pero otras no. A veces Maven es lo suficientemente inteligente para construir recursivamente  proyectos en el orden correcto, pero a veces no.
¡Algunas cosas no son configuradas en el pom.xml!, como los repositorios Maven, los servidores, las credenciales de autentificación, que son configuradas en el fichero settings.xml. Es perfectamente razonable querer mantener el usuario y contraseña fuera del fichero pom.xml pues será comprobado dentro del repositorio de control de versiones del proyecto. Pero Maven tiene una solución terrible, toda la configuración está en el fichero settings.xml que vive fuera de cualquier directorio del proyecto. No puedes compartir directamente cualquiera de las configuraciones entre tu sobremesa y tu portátil, o con cualquier desarrollador, o con el servidor de tu proyecto. Pero es automáticamente compartido con cada proyecto único de Maven con el que trabajes y potencialmente con cada usuario que use el ordenador. Cuando un nuevo desarrollador se una a tu proyecto, deberá cambiar manualmente la configuración necesaria en el fichero settings.xml. Cuando un nuevo agente es añadido a tu granja de servidores, la configuración necesaria es manualmente fusionada en el settings.xml existente. Del mismo modo cuando quieras migrar a un nuevo ordenador. Y cuando cualquiera de estas configuraciones necesiten actualizarse, debe actualizarse manualmente en cada máquina. Esto estaba ya resuelto antes de que Maven llegase, también los archivos de propiedades. Los equipos de los proyectos pueden poner una configuración genérica como está en un fichero ‘properties‘ el cual es comprobado en el control de versiones y un desarrollador puede sobreescribir la información en el fichero ‘properties‘ local, el cual no está comprobado en el control de versiones.
Todas estas cosas en Maven -convenciones, configuraciones y procesos- son gobernados a la manera Maven. Desafortunadamente “la manera Maven” no esta documentada. Puedes encontrar algo fugaz buscando en la documentación de Maven, en Google, o comprando libros escritos por los desarrolladores de Maven. Otra manera de encontrar “la manera Maven” es tropezando con sus invisibles fronteras. Maven no fue creado para ser flexible y no soporta cada posible proceso de creación (‘build’). Fue creado para los proyectos de Apache, y asume todos los procesos espejos de construcción de proyectos de Apache como propios. Es una noticia genial para los desarrolladores open-source quienes voluntariamente en su propio tiempo entienden que liberar (‘release‘)  significa subir un fichero ‘.zip‘ a la web, para que otros manualmente lo encuentren, lo descarguen y lo añadan a sus propios proyectos. Es una faena para todo lo demas. Miestras Rake y Ant pueden acomodarse a cada proceso de construcción, Maven no. Es posible y muy probable que Maven no soporte la manera que tú tienes de construir tu software.
La gestión de dependecias que tiene Maven está completa, total e irrevocablemente rota. Actualmente, retiro lo dicho; la estrategia de Maven de descargar la biblioteca al directorio del usuario y volcarlo en el ‘classpath’ es increiblemente estúpido y equivocado y nunca debería ser confundido con “gestión de dependencias”. Recientemente trabajé con Maven en un proyecto que produjo un fichero ‘.war‘ de 51MB; Cambiando a Ant, con gestión de dependencias, reducimos a menos de 17MB. Hmmmmm 51 -17 = 34 = 17*2 ó 2/3 del tamaño original.
Las dependencias extrañas no solo consumen espacio en disco, consumen también la preciosa RAM. Maven es un traga memoria. Relativamente, proyectos simples, con solo  un pom.xml y unos pocos submódulos requiere una extensa memoria de la JVM con todos las fantásticas opciones de JAVA_OPTS; esto sólo lo puedes ver en los servidores de producción. Las cosas empeoran si tu construcción Maven está integrada en tu IDE. Es muy común aumentar el tamaño de la memoria dinámica de la JVM a cientos de megabytes, el tamaño máximo ‘permgen‘ a unos pocos cientos de megabytes, permitir a ‘permgen‘ generalizar el recolector de basura de las clases. Todo esto para construir tu proyecto o para trabajar con Maven en tu IDE.
Una historia bonita: en ese mismo proyecto, Maven tardó diez minutos en hacer un ‘mvn clean‘ porque pensaba que necesitaba más basura “rm -rf ./target/“. Actualmente no hay ninguna bonita historia, créeme, no quieras contruir una herramienta que automaticamente descarga dependencias no resueltas antes de limpiar los directorios de construcción. Hace tus construciones no deterministicas [teoría que supone que la evolución de los fenómenos naturales está completamente determinada por las condiciones iniciales.]
Y todo innecesariamente, sobrecargando de red. Pagas una penalizacion en el rendimiento, Maven rompe la gestión de dependencias en cada construcción. 10 minutos para limpiar la construcción es horrible, pero añadir unos minutos extra para cada construcción es aún peor. Estimo que la sobrecarga promedio adicional de Maven es de aproximadamente un minuto por cada construcción, basado en el hecho de que la única vez que cambié Maven por Ant, la media del tiempo de construcción se redujo de dos minutos y medio a uno y medio. Similarmente, la vez que cambié de Ant a Maven el tiempo medio aumentó de dos minutos a tres.
No tienes el control, tienes poca visibilidad de lo que pasa dentro, las dependencias se especifican por tus dependencias. Los ‘builds‘ se romperán por las diferentes copias que Maven descargará de diferentes artefactos en diferentes momentos. Tu ‘build‘ local se romperá de nuevo en el futuro cuando las dependencias de tus dependecias acidentalmente lancen nuevas, no compatibles hacia atrás con los cambios, sin recordar poner el número de versión. Estos son fallos inocentes. El escenario más probable que es tu proyecto depende de versiones específicas de algún otro proyecto que tendrá dependencias de versiones antiguas de algún otro proyecto. Cada versión de cada dependencia será una nueva opotunidad para tirar muchas horas rastreando extraños fallos de construcción.
Pero Maven es incluso peor, no solamente resuelve automáticamente las dependencias de tu proyecto, también resuelve automáticamente las dependencias de sus plugins. Así que ahora no sólo tienes que preocuparte por las instancias independientes que Maven descarga accidentalmente de artefactos incompatibles (o que la misma instancia descarga artefactos incompatibles en diferentes momentos), también tienes que preocuparte de construir herramientas que se comporten de manera diferente a través de máquinas diferentes en momentos diferentes.
La mala gestión de dependencias de Maven también tiene un enorme agujero de seguridad, desde el cual actualmente es imposible determinar de donde provienen los artefactos y si han sido o no manipulados. Los artefactos tienen una suma de comprobación (‘checksum‘) automática cuando son subidos a un repositorio, Maven automáticamente verifica que la suma de comprobación cuando descarga el artefacto, pero implicitamente confía la suma de comprobación en el repositorio desde el cual se ha descargado. El alcance actual de la seguridad de los artefactos en Maven es que los desrrolladores de Maven controlan quién tiene acceso de escritura para el repositorio autorizado en la ibiblio. Pero no hay manera de saber si el repositorio del cual descargas todas tus dependencias está envenenado, no hay manera de conocer si la caché de tu repositorio local está envenenada, y no hay manera de conocer de donde proviene el repositorio de artefactos que está en tu caché local.
Estos problemas no son causados por desarrolladores temerarios, y no se solucionan usando un gestor de repositorios para bloquear todo artefacto que Maven necesite. Maven está arruinado y mal enfocado, y asume que los humanos nunca cometen errores. Maven está arruinado y mal enfocado si requieres que los usuarios explícitamente expecifiquen cada versión de cada dependencia, para reducir la probabilidad de descargarse artefactos incompatibles. Maven esta arruinado y mal enfocado si requiere una tercera herramienta para prevenir que se conecte y se descargue mierda. Maven esta arruinado y mal enfocado si piensa que no es lento descargarse cada ‘build conectándode a la red y comprobando cada dependencia de cada actualización y descargándolo automáticamente. Maven está arruinado y mal enfocado si se comporta de manera diferente en mi portátil de la oficina y en el de casa. Maven está arruinado y mal enfocado si requiere una conexión a internet para eliminar un directorio. Maven estáarruinado y mal enfocado.

Principio de la Convencion sobre Configuracion

de la wikipedia

La filosofía general de Maven es la estandarización de las construcciones generadas por seguir el principio de Convención sobre configuración, a fin de utilizar existentes modelos en la producción de software. Esta estrategia necesariamente restringe ampliamente la variabilidad, lo que se refleja en la exhortación de Maven a adherirse a su modelo de proyecto. Mientras que Maven es adecuado para nuevos proyectos, los proyectos complejos ya existentes pueden ser simplemente no adaptables para que utilicen Maven. La falta de restricciones de la convención de capas del proyecto fue hecha de alguna manera más configurable con el lanzamiento de Maven 2.