Following Generic Declarations are good
List<Exception> li = new ArrayList<Exception>();
List<? extends Exception> li = new ArrayList<FileNotFoundException>();
ArrayList<? extends Exception> li = new ArrayList<FileNotFoundException>();
ArrayList<?> li = new ArrayList<FileNotFoundException>();
ArrayList<?> li = new ArrayList<>();
ArrayList<String> li = new ArrayList<>();
List<? super FileNotFoundException> li = new ArrayList<FileNotFoundException>();
List<? super FileNotFoundException> li = new ArrayList<Exception>();
List<? extends Exception> li = new ArrayList<Exception>();
Following declarations result in compile time error
List<Exception> li = new ArrayList<FileNotFoundException>(); // argument type should be same.
ArrayList<Exception> li = new ArrayList<FileNotFoundException>(); // argument type should be same.
List<Exception> li = new List<Exception>(); // List is not a concrete class but an interface
ArrayList<? extends String> li = new ArrayList<FileNotFoundException>(); // FileNotFoundException doesn't extend String
List<> li = new ArrayList<>(); // incorrect argument
List<? super Exception> li = new ArrayList<FileNotFoundException>(); // FileNotFoundException is not super class of Exception