Por que recebo “Exceção; deve ser capturado ou declarado para ser lançado ”quando tento compilar meu código Java?

Considerar:

import java.awt.*; import javax.swing.*; import java.awt.event.*; import javax.crypto.*; import javax.crypto.spec.*; import java.security.*; import java.io.*; public class EncryptURL extends JApplet implements ActionListener { Container content; JTextField userName = new JTextField(); JTextField firstName = new JTextField(); JTextField lastName = new JTextField(); JTextField email = new JTextField(); JTextField phone = new JTextField(); JTextField heartbeatID = new JTextField(); JTextField regionCode = new JTextField(); JTextField retRegionCode = new JTextField(); JTextField encryptedTextField = new JTextField(); JPanel finishPanel = new JPanel(); public void init() { //setTitle("Book - E Project"); setSize(800, 600); content = getContentPane(); content.setBackground(Color.yellow); content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); JButton submit = new JButton("Submit"); content.add(new JLabel("User Name")); content.add(userName); content.add(new JLabel("First Name")); content.add(firstName); content.add(new JLabel("Last Name")); content.add(lastName); content.add(new JLabel("Email")); content.add(email); content.add(new JLabel("Phone")); content.add(phone); content.add(new JLabel("HeartBeatID")); content.add(heartbeatID); content.add(new JLabel("Region Code")); content.add(regionCode); content.add(new JLabel("RetRegionCode")); content.add(retRegionCode); content.add(submit); submit.addActionListener(this); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand() == "Submit"){ String subUserName = userName.getText(); String subFName = firstName.getText(); String subLName = lastName.getText(); String subEmail = email.getText(); String subPhone = phone.getText(); String subHeartbeatID = heartbeatID.getText(); String subRegionCode = regionCode.getText(); String subRetRegionCode = retRegionCode.getText(); String concatURL = "user=" + subUserName + "&f=" + subFName + "&l=" + subLName + "&em=" + subEmail + "&p=" + subPhone + "&h=" + subHeartbeatID + "&re=" + subRegionCode + "&ret=" + subRetRegionCode; concatURL = padString(concatURL, ' ', 16); byte[] encrypted = encrypt(concatURL); String encryptedString = bytesToHex(encrypted); content.removeAll(); content.add(new JLabel("Concatenated User Input -->" + concatURL)); content.add(encryptedTextField); setContentPane(content); } } public static byte[] encrypt(String toEncrypt) throws Exception{ try{ String plaintext = toEncrypt; String key = "01234567890abcde"; String iv = "fedcba9876543210"; SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(toEncrypt.getBytes()); return encrypted; } catch(Exception e){ } } public static byte[] decrypt(byte[] toDecrypt) throws Exception{ String key = "01234567890abcde"; String iv = "fedcba9876543210"; SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] decrypted = cipher.doFinal(toDecrypt); return decrypted; } public static String bytesToHex(byte[] data) { if (data == null) { return null; } else { int len = data.length; String str = ""; for (int i=0; i<len; i++) { if ((data[i]&0xFF) < 16) str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF); else str = str + java.lang.Integer.toHexString(data[i]&0xFF); } return str; } } public static String padString(String source, char paddingChar, int size) { int padLength = size-source.length() % size; for (int i = 0; i < padLength; i++) { source += paddingChar; } return source; } } 

Estou recebendo uma exceção não declarada:

 java.lang.Exception; must be caught or declared to be thrown byte[] encrypted = encrypt(concatURL); 

Assim como:

 .java:109: missing return statement 

Como resolvo esses problemas?

Todos os seus problemas derivam disso

 byte[] encrypted = cipher.doFinal(toEncrypt.getBytes()); return encrypted; 

Que são colocados em um try, catch block, o problema é que, caso o programa tenha encontrado uma exceção, você não está retornando nada. Coloque-o assim (modifique-o como a lógica do seu programa está):

 public static byte[] encrypt(String toEncrypt) throws Exception{ try{ String plaintext = toEncrypt; String key = "01234567890abcde"; String iv = "fedcba9876543210"; SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE,keyspec,ivspec); byte[] encrypted = cipher.doFinal(toEncrypt.getBytes()); return encrypted; } catch(Exception e){ return null; // Always must return something } } 

Para o segundo, você deve capturar a Exceção da chamada do método encrypt , assim (também modifique-a como a lógica do seu programa está):

 public void actionPerformed(ActionEvent e) . . . try { byte[] encrypted = encrypt(concatURL); String encryptedString = bytesToHex(encrypted); content.removeAll(); content.add(new JLabel("Concatenated User Input -->" + concatURL)); content.add(encryptedTextField); setContentPane(content); } catch (Exception exc) { // TODO: handle exception } } 

As lições que você deve aprender com isso:

  • Um método com um tipo de retorno deve sempre retornar um object desse tipo, ou seja, em todos os cenários possíveis
  • Todas as exceções verificadas devem sempre ser tratadas

O problema está neste método:

  public static byte[] encrypt(String toEncrypt) throws Exception{ 

Esta é a assinatura do método que praticamente diz:

  • qual é o nome do método: criptografar
  • qual parâmetro ele recebe: uma String nomeada paraEncrypt
  • seu modificador de access: public static
  • e se pode ou não lançar uma exceção quando invocado.

Nesse caso, a assinatura do método diz que, quando invocado, esse método “poderia” potencialmente lançar uma exceção do tipo “Exceção”.

  .... concatURL = padString(concatURL, ' ', 16); byte[] encrypted = encrypt(concatURL); < -- HERE!!!!! String encryptedString = bytesToHex(encrypted); content.removeAll(); ...... 

Então os compiladores estão dizendo: Ou você rode isso com uma construção try / catch ou declara o método (onde está sendo usado) para lançar "Exception".

O problema real é a definição do método "criptografar". Nenhum método deve retornar "Exceção", porque é muito genérico e pode esconder alguns outros tipos de exceção melhor é ter uma exceção específica.

Tente isto:

 public static byte[] encrypt(String toEncrypt) { try{ String plaintext = toEncrypt; String key = "01234567890abcde"; String iv = "fedcba9876543210"; SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE,keyspec,ivspec); byte[] encrypted = cipher.doFinal(toEncrypt.getBytes()); return encrypted; } catch ( NoSuchAlgorithmException nsae ) { // What can you do if the algorithm doesn't exists?? // this usually won't happen because you would test // your code before shipping. // So in this case is ok to transform to another kind throw new IllegalStateException( nsae ); } catch ( NoSuchPaddingException nspe ) { // What can you do when there is no such padding ( whatever that means ) ?? // I guess not much, in either case you won't be able to encrypt the given string throw new IllegalStateException( nsae ); } // line 109 won't say it needs a return anymore. } 

Basicamente, neste caso em particular, você deve certificar-se de que o pacote de criptografia esteja disponível no sistema.

Java precisa de uma extensão para o pacote de criptografia, portanto, as exceções são declaradas como exceções "verificadas". Para você lidar quando eles não estão presentes.

Neste pequeno programa você não pode fazer nada se o pacote de criptografia não estiver disponível, então você verifica isso no tempo de "desenvolvimento". Se essas exceções são lançadas quando seu programa está rodando é porque você fez algo errado em "desenvolvimento", então uma subclass RuntimeException é mais apropriada.

A última linha não precisa mais de uma instrução de retorno, na primeira versão você estava pegando a exceção e não fazendo nada com ela, está errado.

 try { // risky code ... } catch( Exception e ) { // a bomb has just exploited // you should NOT ignore it } // The code continues here, but what should it do??? 

Se o código falhar, é melhor falhar rápido

Aqui estão algumas respostas relacionadas:

  • Captura de exceções em Java

  • Quando escolher exceções marcadas e não verificadas

  • Por que você não tem que declarar explicitamente que pode lançar algumas exceções embutidas em Java?

  • Exceção diferente de RuntimeException

O primeiro erro

java.lang.Exception; deve ser capturado ou declarado para ser lançado byte [] encrypted = encrypt (concatURL);

significa que seu método encrypt lança uma exceção que não está sendo manipulada ou declarada pelo método actionPerformed qual você está chamando. Leia tudo sobre isso no Java Exceptions Tutorial .

Você tem algumas opções que você pode escolher para obter o código para compilar.

  • Você pode remover throws Exception do seu método de encrypt e realmente manipular a exceção dentro da encrypt .
  • Você pode remover o bloco try / catch da encrypt e adicionar o exceção actionPerformed e o bloco de exception handling ao seu método actionPerformed .

Geralmente, é melhor lidar com uma exceção no nível mais baixo possível, em vez de passá-la para um nível mais alto.

O segundo erro significa apenas que você precisa adicionar uma declaração de retorno a qualquer método que contenha a linha 109 (também encrypt , neste caso). Há uma instrução de retorno no método, mas se uma exceção for lançada, ela pode não ser alcançada, portanto, você precisa retornar no bloco catch ou remover o try / catch de encrypt , como mencionei antes.

Você precisará decidir como gostaria de lidar com as exceções geradas pelo método de encrypt .

Atualmente, a encrypt é declarada com throws Exception – no entanto, no corpo do método, as exceções são capturadas em um bloco try / catch. Eu recomendo que você:

  • remover a cláusula throws Exception de encrypt e tratar exceções internamente ( considere escrever uma mensagem de log no mínimo ); ou,
  • remova o bloco try / catch do corpo da encrypt e actionPerformed a chamada para encrypt com um try / catch (isto é, em actionPerformed ).

Em relação ao erro de compilation, você se refere a: se uma exceção foi lançada no bloco try de encrypt , nada é retornado após o bloqueio do bloco catch . Você poderia resolver isso inicialmente declarando o valor de retorno como null :

 public static byte[] encrypt(String toEncrypt) throws Exception{ byte[] encrypted = null; try { // ... encrypted = ... } catch(Exception e){ // ... } return encrypted; } 

No entanto, se você puder corrigir o problema maior (a estratégia de tratamento de exceções), esse problema cuidará de si mesmo – especialmente se você escolher a segunda opção que sugeri.

Em seu método ‘encrypt’, você deve se livrar do try / catch e, em vez disso, adicionar um try / catch em torno de onde você chama encrypt (dentro de ‘actionPerformed’) ou retornar null dentro da captura dentro de criptografar (esse é o segundo erro.

Em actionPerformed(ActionEvent e) você chama encrypt() , que é declarado para lançar Exception . No entanto, actionPerformed não captura essa exceção (com try / catch em torno da chamada para encrypt() ) nem declara que ele lança a própria Exception .

Seu método de encrypt , no entanto, não lança realmente uma Exception . Ele engole todas as exceções, mesmo sem registrar uma reclamação. (Má prática e mau estilo!)

Além disso, seu método de encrypt faz o seguinte:

 public static byte[] encrypt(String toEncrypt) throws Exception { try{ .... return encrypted; // HERE YOU CORRECTLY RETURN A VALUE } catch(Exception e) { } // YOU DO NOT RETURN ANYTHING HERE } 

Ou seja, se você detectar qualquer exceção, você a descartará silenciosamente e, em seguida, cairá da parte inferior do método de encrypt sem realmente retornar nada. Isso não irá compilar (como você vê), porque um método que é declarado para retornar um valor deve retornar um valor ou lançar uma exceção para cada caminho de código possível.