1 - Isso não funciona, se tentar, gera erro:
List<> al = new ArrayList();
O compilador espera o nome de um tipo ali entre < e >.
2 - Isso funciona, porém, se usar assim, estará abrindo mão de um recurso muito útil que são os Generics.
List al = new ArrayList<>();
// sem o <> é o mesmo resultado:
List al = new ArrayList();
Uma lista não-genérica aceita qualquer tipo de objeto.
List l = new ArrayList();
l.add("uma string");
l.add(123);
l.add(new JFrame());
Isso pode ser um problema, pois normalmente o que se deseja é uma lista de objetos que tenham alguma relação entre si.
Por exemplo, num app de lista telefonica vc iria querer uma lista apenas de Contatos. Num app de restaurante vc iria querer uma lista apenas de Pratos.
Generics nos permite limitar o tipo de dado que queremos em nossa lista.
// Aceita só String
List<String> a = new ArrayList<String>();
// Só números inteiros
List<Integer> b = new ArrayList<Integer>();
// Só Contatos
List<Contatos> c = new ArrayList<Contatos>();
// É possível omitir o tipo na instanciação das classes
// o resultado é o mesmo que no trecho acima.
List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
List<Contatos> c = new ArrayList<>();
O uso de Generics vai além disso. É possível criar métodos genéricos também. E quando vc não sabe exatamente com que tipo vc está lidando, pode usar wildcards. Recomendo o tutorial abaixo para maiores informações:
https://docs.oracle.com/javase/tutorial/extra/generics/index.html