Diferença entre instancia e tipos (interface)

Estou estudando coleções em Java e fiquei com uma dúvida.
Na prática, qual a diferença de usar as seguintes instanciações:
Set lista= new HashSet();
e
HashSet lista= new HashSet(); ?

E também:
Map<Integer, String> lista= new HashMap();
e
HashMap<Integer, String> lista= new HashMap(); ?

Quando usar a inteface para definir o tipo e quando não usar?
Na teoria, com o uso das interfaces teríamos métodos limitados, isto é, apenas aqueles contidos da interface. Diferente quando utilizamos o tipo e instância iguais, tendo os todos os métodos disponíveis.

Seguinte.

Tipo tem uma função elementar de qualificar para você, para o compilador e para o rumtime um objeto de operação (variável ou parâmetro).

Para você, nem preciso falar, pois saberá quais operações e atributos poderá acessar pelo tipo declarado. Isso não é óbvio quando um tipo é mais genérico do que a instância. Se o tipo for mais genérico, menos especializado ou abstrato, logo você terá um acesso limitado a instância podendo acessar somente as operações e atributos definidos na classe declarada como tipo.

Para o compilador, ele será transformado num endereço linkado a classe do tipo.

Para o runtime, ele será uma indicação inicial para descobrir o quanto deverá ser alocado de memória caso esteja ligado a uma instância. Em caso do tipo ser uma referência a outra variável, então a alocação de memória não será realizada.

Você optou por definir o tipo Set e instanciar HashSet que implementa Set. Conseguiu fazer isso por causa do princípio de herança e polimorfismo da O.O. No caso, mesmo que HashSet tenha implementado operações a mais do que Set obrigou, você só conseguirá acessar as operações disponíveis em Set.

Na segunda forma, você simplismente preferiu definir a propria classe da instância como tipo e ter acesso completo de todas as operações públicas da instância sem nenhum filtro.

O princípio aqui é o mesmo de “Set lista= new HashSet()”. Só que você deveria indicar ao construir a instância os dois Generics informados em Map<Integer, String> e HashMap<Integer, String>. Isso evita do Java ter que perder tempo descobrindo quais são as classes para estes Generics.

Normalmente a interface serve para você prototipar as operações de uma classe antes dela ser construída. Imagina você sendo um projetista de sistemas, você sabe que precisará definir uma estrutura de operações de uma ou mais classes, mas sabe que não é você quem implementará as operações. Neste caso, você fará a interface para o desenvolvedor manter as estruturas de operações que você determinou. No dia-a-dia de uma boa organização, isso simplifica e elimina riscos de execução do projeto.