Eu sou bem velha. Eu estive lá e vi e bati minha cabeça sobre isso muitas vezes.
Eu estava em uma conferência em Hursley Park, onde os garotos da IBM estavam nos dizendo o quão maravilhosa essa nova linguagem Java era, apenas alguém perguntou ... por que não existe um destruidor para esses objetos? Ele não quis dizer o que conhecemos como destruidor em C ++, mas também não havia finalizador (ou ele tinha finalizadores, mas eles basicamente não funcionaram). Isso está de volta e decidimos que o Java era um pouco de uma linguagem de brinquedo naquele momento.
agora eles adicionaram finalizadores à especificação da linguagem e o Java viu alguma adoção.
Obviamente, mais tarde todos foram instruídos a não colocar finalizadores em seus objetos, porque isso diminuiu tremendamente o GC. (como era necessário não apenas bloquear a pilha, mas mover os objetos a serem finalizados para uma área temporária, pois esses métodos não podiam ser chamados porque o GC interrompeu a execução do aplicativo. Em vez disso, eles seriam chamados imediatamente antes da próxima Ciclo do GC) (e pior, às vezes o finalizador nunca seria chamado quando o aplicativo estava sendo desligado. Imagine nunca ter o identificador de arquivos fechado)
Em seguida, tínhamos C #, e lembro-me do fórum de discussão no MSDN, onde nos disseram como era maravilhosa essa nova linguagem C #. Alguém perguntou por que não havia finalização determinística e os meninos do MS nos disseram que não precisávamos de tais coisas, depois nos disseram que precisávamos mudar nossa maneira de projetar aplicativos, depois nos disseram o quão incrível era o GC e como todos os nossos aplicativos antigos eram. lixo e nunca funcionou por causa de todas as referências circulares. Então eles cederam à pressão e nos disseram que haviam adicionado esse padrão IDispose às especificações que poderíamos usar. Eu pensei que estava praticamente voltando ao gerenciamento manual de memória para nós em aplicativos C # naquele momento.
É claro que os garotos do MS descobriram mais tarde que tudo o que haviam nos dito era ... bem, eles fizeram do IDispose um pouco mais do que apenas uma interface padrão e depois adicionaram a instrução using. W00t! Eles perceberam que a finalização determinística era algo que faltava na linguagem, afinal. Claro, você ainda precisa se lembrar de colocá-lo em qualquer lugar, por isso ainda é um pouco manual, mas é melhor.
Então, por que eles fizeram isso quando poderiam ter colocado semânticas de estilo de uso automaticamente colocadas em cada bloco de escopo desde o início? Provavelmente eficiência, mas gosto de pensar que eles simplesmente não perceberam. Assim como acabaram percebendo que você ainda precisa de indicadores inteligentes no .NET (google SafeHandle), eles pensaram que o GC realmente resolveria todos os problemas. Eles esqueceram que um objeto é mais do que apenas memória e que o GC foi projetado principalmente para lidar com o gerenciamento de memória. eles se envolveram com a idéia de que o GC lidaria com isso e esqueceram que você colocava outras coisas lá, um objeto não é apenas uma bolha de memória que não importa se você não o excluir por um tempo.
Mas também acho que a falta de um método finalize no Java original tinha um pouco mais - que os objetos que você criou eram todos sobre memória e se você queria excluir outra coisa (como um identificador de banco de dados, um soquete ou qualquer outra coisa) ), esperava-se que você o fizesse manualmente .
Lembre-se de que o Java foi projetado para ambientes incorporados em que as pessoas estavam acostumadas a escrever código C com muitas alocações manuais, portanto, não ter o acesso automático gratuito não era um grande problema - eles nunca fizeram isso antes, então por que você precisaria dele em Java? O problema não tinha nada a ver com threads ou pilha / pilha, provavelmente estava lá apenas para facilitar a alocação de memória (e, portanto, a desalocação). Ao todo, a instrução try / finalmente é provavelmente um lugar melhor para lidar com recursos que não são de memória.
Então, IMHO, a maneira como o .NET simplesmente copiou a maior falha de Java é sua maior fraqueza. O .NET deveria ter sido um C ++ melhor, não um Java melhor.