Também me ensinaram isso e prefiro interfaces sempre que possível (é claro que ainda uso herança onde faz sentido).
Uma coisa que eu acho que faz é separar seu código de implementações específicas. Digamos que eu tenha uma classe chamada ConsoleWriter e que seja passada para um método para escrever algo e que seja gravado no console. Agora, digamos que eu queira mudar para a impressão em uma janela da GUI. Bem, agora eu tenho que modificar o método ou escrever um novo que use o GUIWriter como parâmetro. Se eu iniciasse definindo uma interface IWriter e tivesse o método em um IWriter, poderia começar com o ConsoleWriter (que implementaria a interface IWriter) e depois escrever uma nova classe chamada GUIWriter (que também implementa a interface IWriter) e então eu teria apenas que mudar a classe que estava sendo aprovada.
Outra coisa (o que é verdade para C #, não tenho certeza sobre Java) é que você só pode estender 1 classe, mas implementar muitas interfaces. Digamos que eu tive aulas denominadas Teacher, MathTeacher e HistoryTeacher. Agora MathTeacher e HistoryTeacher se estendem do Teacher, mas e se quisermos uma classe que represente alguém que seja um MathTeacher e HistoryTeacher. Pode ficar bastante confuso ao tentar herdar de várias classes quando você pode fazê-lo apenas uma de cada vez (existem maneiras, mas elas não são exatamente ideais). Com interfaces, você pode ter 2 interfaces chamadas IMathTeacher e IHistoryTeacher e, em seguida, ter uma classe que se estende do Teacher e implementa essas 2 interfaces.
Uma desvantagem do uso de interfaces é que, às vezes, vejo pessoas duplicar código (já que você precisa criar a implementação para cada classe, implementar a interface), no entanto, existe uma solução limpa para esse problema, por exemplo, o uso de coisas como delegados (não tenho certeza qual o Java equivalente a isso).
O principal motivo para usar interfaces sobre heranças é a dissociação do código de implementação, mas não pense que a herança seja ruim, pois ainda é muito útil.