Segundo os princípios de orientação a objeto, cada classe deve ter uma funcionalidade bem definida, que realmente represente um objeto. Isso e o bom senso é o que deve ser considerado na hora de desenhar sua aplicação.
Um livro que aborda esse assunto de inner classes de forma muito interessante é a última edição do Thinking In Java, disponível em http://www.bruceeckel.com/Books. Lá você vai ver alguns dos casos mais viajantes em que faz sentido você criar uma inner class. Coisas que você nem conseguiria fazer sem elas.
Mas o que às vezes é meio complexo para se entender sobre inner classes é que elas podem existir das mais diversas formas, e cada uma tem um funcionamento bem diferente. O primeiro tipo seria criar uma classe comum como membro de outra classe. Nesse caso, a vantagem é que essa inner class tem acesso a todos os membros da classe externa, incluindo os private. O que acontece nesse caso é que os objetos da inner class ficam associados ao objeto da classe externa, e pode manipulá-lo através de seus métodos. Seria quase como criar os métodos na própria classe, mas com a vantagem de deixar o cógido mais organizado. Uma aplicação comum para essa estratégia é fazer as classes listener de uma interface gráfica.
Outro caso seriam inner classes dentro de métodos. Aí normalmente é usado só para adicionar umas funcionalidades ao método em questão, novamente aproveirando a idéia de poder acessar todos os membros da classe externa de dentro dessa classe interna. Só precisa tomar cuidado nesse caso com o fato de NÃO poder utilizar as variáveis locais do método, exceto se elas estiverem marcadas como final (devido ao objeto e das variáveis do método ficarem em áreas diferentes da memória).
Um terceiro tipo são as inner classes static. Nesse caso, ela acaba tento um comportamento igual a qualquer classe comum e não tem esse acesso especial a classe externa, uma vez que é static e portanto não está relacionada a nenhuma instância.
E por fim existem as classes anonimas, discutidas no outro tópico. Quando você declara uma classe anônima, ela é sempre uma subclasse do tipo em que foi declarada. Aí uma vantagem é você poder fazer override de alguns métodos para aquele objeto específico (por exemplo, a classe pai realiza um método de determinada forma, mas você quer uma classe em que seja tudo igua exceto aquele método, então cria essa classe anônima e faz override do método em questão para o comportamento que você precisa).
Bom, tem muito mais que dá para ser feito com inner classes, e lendo o livro no link que indiquei acima dá para começar a ter uma idéia melhor do assunto.