Em Java, para que exceções verificadas são boas? [fechadas]

14

As exceções verificadas de Java receberam críticas negativas ao longo dos anos. Um sinal revelador é que é literalmente a única linguagem no mundo que os possui (nem mesmo outras linguagens da JVM, como Groovy e Scala). Bibliotecas proeminentes de Java, como Spring e Hibernate, também não as utilizam.

Eu pessoalmente encontrei um uso para eles ( na lógica de negócios entre as camadas), mas, por outro lado, sou bonita exceções anti-checagem.

Existem outros usos que eu não percebo?

    
por Brad Cupit 16.11.2010 / 02:42
fonte

8 respostas

22
Primeiro de tudo, como qualquer outro paradigma de programação, você precisa fazer certo para que funcione bem.

Para me , a vantagem das exceções verificadas é que os autores da biblioteca de tempo de execução Java JÁ decidiram por mim quais problemas comuns eu poderia razoavelmente esperar serem capazes de manipular na chamada apontar (ao contrário de um bloco de captura de topo-nível-dado) e considerar o mais cedo possível como lidar com estes problemas.

Eu gosto de exceções verificadas porque elas tornam meu código mais robusto, forçando-me a pensar na recuperação de erros o mais cedo possível.

Para ser mais preciso, me isso torna meu código mais robusto, pois me obriga a considerar casos esquisitos muito cedo no processo, em vez de dizer "Opa, meu código não funciona se o arquivo ainda não existe "com base em um erro na produção, que você terá que refazer seu código para manipular. Adicionar manipulação de erros ao código existente pode ser uma tarefa não trivial - e, portanto, cara - ao atingir a manutenção, em vez de apenas fazer isso desde o início.

Pode ser que o arquivo que está faltando seja fatal e faça o programa cair em chamas, mas você toma essa decisão com

} catch (FileNotFoundException e) {
  throw new RuntimeException("Important file not present", e);
}

Isso também mostra um efeito colateral muito importante. Se você quebrar uma exceção, você pode adicionar uma explicação que vai no stack-trace ! Isso é extremamente poderoso porque você pode adicionar informações sobre o nome do arquivo que estava faltando, ou os parâmetros passados para este método ou outras informações de diagnóstico, e essa informação está presente diretamente no rastreamento de pilha que freqüentemente é a única coisa que você obtém quando um programa tem caiu.

As pessoas podem dizer "podemos simplesmente executar isso no depurador para reproduzir", mas descobri que erros de produção muito frequentemente não podem ser reproduzidos mais tarde, e não podemos executar depuradores em produção, exceto para muito casos desagradáveis em que essencialmente seu trabalho está em jogo.

Quanto mais informações no seu rastreamento de pilha, melhor. As exceções verificadas ajudam-me a obter essas informações lá e no início.

EDIT: Isso vale também para designers de bibliotecas. Uma biblioteca que uso diariamente contém muitas, muitas exceções verificadas que poderiam ter sido projetadas muito melhor, tornando menos tedioso o uso.

    
por 16.11.2010 / 06:13
fonte
11

Você tem duas boas respostas que explicam quais exceções verificadas se tornaram práticas. (+1 para ambos.) Mas também valeria a pena examinar o que eles pretendiam em teoria, porque a intenção realmente vale a pena.

As exceções verificadas destinam-se a tornar a linguagem mais segura. Considere um método simples como a multiplicação de inteiros. Você pode pensar que o tipo de resultado desse método seria um inteiro, mas, estritamente falando, o resultado é um inteiro ou uma exceção de estouro. Considerando o resultado inteiro por si só como o tipo de retorno do método não expressa o intervalo completo da função.

Visto a esta luz, não é estritamente verdadeiro dizer que as exceções verificadas não foram encontradas em outros idiomas. Eles simplesmente não tomaram a forma que o Java usou. Em aplicativos Haskell, é comum usar tipos de dados algébricos para distinguir entre a conclusão bem-sucedida e malsucedida da função. Embora isso não seja uma exceção, por si só, a intenção é muito parecida com uma exceção verificada; é uma API projetada para forçar o consumidor da API a lidar com o sucesso no caso malsucedido, por exemplo:

data Foo a =
     Success a
   | DidNotWorkBecauseOfA
   | DidNotWorkBecauseOfB

Isto diz ao programador que a função tem dois resultados adicionais possíveis além do sucesso.

    
por 16.11.2010 / 03:34
fonte
11

IMO, exceções verificadas são uma implementação defeituosa do que pode ter sido uma idéia bastante decente (sob circunstâncias completamente diferentes - mas na verdade nem é uma boa idéia na circunstância atual).

A boa idéia é que seria bom que o compilador verifique se todas as exceções que um programa tem potencial para lançar serão capturadas. A implementação falha é que, para fazer isso, o Java força você a lidar com a exceção diretamente em qualquer classe que invoca qualquer coisa que seja declarada para lançar uma exceção verificada. Uma das idéias mais básicas (e vantagens) do tratamento de exceções é que, no caso de um erro, ele permite camadas intermediárias de código que não têm nada a ver com um erro específico, para ignorar completamente sua própria existência. As exceções verificadas (conforme implementadas em Java) não permitem isso, destruindo, assim, uma vantagem principal (a principal?) Do tratamento de exceções para começar.

Em teoria, eles poderiam ter tornado úteis as exceções verificadas aplicando-as apenas em uma base de programa amplo - ou seja, enquanto "construía" o programa, construísse uma árvore de todos os caminhos de controle no programa. Vários nós na árvore seriam anotados com 1) exceções que eles podem gerar, e 2) exceções que eles podem capturar. Para assegurar que o programa estava correto, você caminharia pela árvore, verificando se todas as exceções lançadas em qualquer nível da árvore foram capturadas em algum nível superior da árvore.

A razão pela qual eles não fizeram isso (eu acho, pelo menos) é que isso seria extremamente difícil - na verdade, duvido que alguém tenha escrito um sistema de compilação que possa fazer isso. para qualquer coisa, mas extremamente simples (na fronteira de "brinquedo") idiomas / sistemas. Para o Java, coisas como o carregamento dinâmico de classes tornam isso ainda mais difícil do que em muitos outros casos. Pior, (ao contrário de algo como C) Java não é (pelo menos normalmente) estaticamente compilado / ligado a um executável. Isso significa que nada no sistema realmente tem a percepção global de que até tente fazer esse tipo de imposição até que o usuário final realmente comece a carregar o programa para executá-lo.

Fazer aplicação nesse ponto é impraticável por alguns motivos. Em primeiro lugar, mesmo na melhor das hipóteses, estenderia os tempos de inicialização, que já são uma das maiores e mais comuns reclamações sobre o Java. Segundo, para fazer muito bem, você realmente precisa detectar o problema com antecedência suficiente para que um programador o conserte. Quando o usuário está carregando o programa, é tarde demais para fazer muito bem - suas únicas escolhas nesse momento são ignorar o problema, ou se recusar a carregar / rodar o programa, na chance de que possa é uma exceção que não foi detectada.

Como elas são, exceções verificadas são piores do que inúteis, mas projetos alternativos para exceções verificadas são ainda piores. Embora a ideia básica para exceções verificadas pareça boa, ela não é realmente muito boa e, por acaso, é um ajuste particularmente ruim para Java. Para algo como C ++, que normalmente é compilado / vinculado em um executável completo com nada parecido com reflexão / carga dinâmica de classe, você teria um pouco mais de chance (embora, francamente, mesmo aplicando-os corretamente sem o mesmo tipo de confusão eles causa atualmente em Java ainda estaria provavelmente além do atual estado da arte).

    
por 16.11.2010 / 05:33
fonte
10

Eles são realmente bons para programadores irritantes e estimulam a ingestão de exceções. Metade do ponto de exceção é que você tem uma maneira padrão de lidar com os erros e não precisa pensar em propagar explicitamente as condições de erro que não pode manipular. (O padrão normal é que, se você nunca manipular o erro em qualquer parte de seu código, você efetivamente afirmou que isso não pode acontecer e fica com uma saída sensata e um rastreamento de pilha se estiver errado.) Exceção das exceções verificadas isto. Eles se sentem muito como ter que propagar explicitamente erros em C.

    
por 16.11.2010 / 02:47
fonte
5

Acho justo dizer que as exceções verificadas foram um pouco um experimento falho. Onde eles erraram é que eles quebraram camadas:

  • O módulo A pode ser construído no topo do módulo B, onde
  • O módulo B pode ser construído no topo do Módulo C.
  • O Módulo C pode saber como identificar um erro e
  • O Módulo A pode saber como lidar com o erro.

A boa separação de interessados está quebrada, porque agora o conhecimento de erros que poderiam ter sido limitados a A e C agora tem que ser espalhados por B.

Há uma discussão agradável de exceções verificadas na Wikipedia.

E Bruce Eckel também tem um artigo legal . Aqui está uma citação:

[T]he more random rules you pile onto the programmer, rules that have nothing to do with solving the problem at hand, the slower the programmer can produce. And this does not appear to be a linear factor, but an exponential one

Eu acredito que para o caso do C ++, se todos os métodos tiverem a cláusula throws specification, então você pode ter algumas otimizações legais. Eu não acredito que o Java possa ter essas vantagens de qualquer maneira, porque RuntimeExceptions não está marcado. Um JIT moderno deve ser capaz de otimizar o código de qualquer maneira.

Um bom recurso do AspectJ é a suavização de exceção: você pode transformar as exceções verificadas em exceções não verificadas, especificamente para aprimorar a disposição em camadas.

Talvez seja irônico que o Java tenha passado por todos esses problemas, quando poderia ter verificado por null , que poderia tem sido muito mais valioso .

    
por 16.11.2010 / 03:07
fonte
5

Eu amo exceções.

Estou, no entanto, constantemente confuso com a falta de uso deles.

  1. Não os use para manuseio de fluxo. Você não quer código que tente fazer alguma coisa e usa uma exceção como um gatilho para fazer outra coisa, em vez disso, porque exceções são objetos que precisam ser criados e usam a memória, etc. etc., só porque você não poderia se incomodar em escrever tipo de if () verifique antes de fazer sua ligação. Isso é apenas preguiçoso e dá à gloriosa Exceção um nome ruim.

  2. Não os engula. Sempre. Em qualquer circunstância. Como um mínimo absoluto, você coloca algo em seu arquivo de log para indicar que uma Exceção aconteceu. Tentar rastrear seu caminho através de código que engula exceções é um pesadelo. Mais uma vez, amaldiçoe os engolidores de exceção por trazer a Poderosa Exceção ao descrédito!

  3. Trate Exceções com seu chapéu OO. Crie seus próprios objetos Exception com hierarquias significativas. Layer sua lógica de negócios e suas exceções de mãos dadas. Eu costumava achar que, se eu começasse em uma nova área de um sistema, eu encontraria a necessidade de subclassificar Exception dentro de meia hora de codificação, de modo que nestes dias eu comecei escrevendo as classes Exception.

  4. Se você estiver escrevendo trechos de código 'frameworky', certifique-se de que todas as suas interfaces iniciais sejam escritas para lançar suas próprias novas Exceções, quando apropriado ... e certifique-se de que seus codificadores tenham algum código de amostra no lugar de o que fazer quando o código lança uma IOException, mas a interface para a qual eles estão escrevendo quer lançar uma 'ReportingApplicationException'.

Uma vez que você explodiu a maneira de fazer as Exceções funcionarem para você, você nunca olhará para trás.

    
por 18.11.2010 / 16:58
fonte
4

As exceções verificadas também estão no ADA.

(Aviso, este post contém crenças strongmente defendidas que você pode encontrar em confronto.)

Programadores não gostam deles e reclamam, ou escrevem código de deglutição de exceção.

As exceções verificadas existem porque as coisas podem não apenas deixar de funcionar, você pode fazer uma análise do modo de falha / efeitos e determinar isso com antecedência.

As leituras de arquivos podem falhar. Chamadas RPC podem falhar. O IO da rede pode falhar. Os dados podem ser formatados incorretamente quando analisados.

O "caminho feliz" para o código é fácil.

Eu conheci um cara na Universidade que poderia escrever um ótimo código de "caminho feliz". Nenhum dos casos de borda funcionou. Atualmente, ele faz Python para uma empresa de código aberto. Nuff disse.

Se você não quiser lidar com exceções verificadas, o que você está realmente dizendo é

While I'm writing this code, I don't want to consider obvious failure modes.

The User will just have to like the program crashing or doing weird things.

But that's okay with me because 

I'm so much more important than the people who will have to use the software

in the real, messy, error-prone world.

After all, I write the code once, you use it all day long.

Assim, as exceções verificadas não serão apreciadas pelos programadores, porque significa mais trabalho.

Claro, outras pessoas podem ter desejado esse trabalho.

Eles podem ter desejado a resposta certa, mesmo se o servidor de arquivos falhou / USB morre.

É uma crença estranha na comunidade de programação que você deve usar uma linguagem de programação que facilite sua vida, que você goste, quando seu trabalho é escrever software. Seu trabalho é resolver o problema de alguém, não permitindo que você se envolva em improvisações programáticas de Jazz.

Se você é um programador amador (não está programando por dinheiro), sinta-se à vontade para programar em C # ou em outro idioma sem exceções verificadas. Heck, corte o intermediário e programe no Logo. Você pode desenhar padrões bonitos no chão com a tartaruga.

    
por 16.11.2010 / 03:46
fonte
4

As exceções verificadas devem ter incentivado as pessoas a lidarem com erros próximos a essa fonte. Quanto mais distante da fonte, mais funções terminaram no meio da execução e mais provável é que o sistema tenha entrado em um estado inconsistente. Além disso, é mais provável que você pegue a exceção errada por acidente.

Infelizmente, as pessoas tendem a ignorar exceções ou adicionar especificações de lançamento cada vez maiores. Ambos perdem o ponto do que se espera que as exceções sejam encorajadas. Eles são como transformar código processual para usar muitas funções Getter e Setter, supostamente tornando-o OO.

Essencialmente, as exceções verificadas estão tentando provar um certo grau de correção em seu código. É praticamente a mesma ideia que tipagem estática, na medida em que tenta provar que certas coisas estão corretas antes mesmo de o código ser executado. O problema é que todas essas provas extras exigem esforço e o esforço vale a pena?

    
por 16.11.2010 / 05:12
fonte