Почему я получаю «Исключение; должен быть перехвачен или объявлен как выброшенный», когда я пытаюсь скомпилировать свой код Java? - PullRequest
35 голосов
/ 26 мая 2009

Рассмотрим:

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;
    }
}

Я получаю незарегистрированное исключение:

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

А также:

.java:109: missing return statement

Как мне решить эти проблемы?

Ответы [ 6 ]

31 голосов
/ 26 мая 2009

Все ваши проблемы проистекают из этого

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

Которые заключены в блок try, catch, проблема в том, что если программа обнаружила исключение, вы ничего не возвращаете. Поместите это так (измените его, как логика вашей программы стоит):

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
    }
}

Для второго вы должны перехватить исключение из вызова метода encrypt , например, (также измените его в соответствии с логикой вашей программы):

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
    }
}

Уроки, которые вы должны извлечь из этого:

  • Метод с типом возврата должен всегда возвращать объект этого типа, я имею в виду во всех возможных сценариях
  • Все отмеченные исключения должны всегда обрабатываться
6 голосов
/ 26 мая 2009

Проблема в этом методе:

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

Это сигнатура метода , которая в значительной степени говорит:

  • как называется метод: encrypt
  • какой параметр он получает: строка с именем toEncrypt
  • его модификатор доступа: public static
  • и может или нет выбросить исключение при вызове.

В этом случае подпись метода говорит, что при вызове этот метод «мог» потенциально вызвать исключение типа «Исключение».

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

Таким образом, компиляторы говорят: либо вы окружаете это конструкцией try / catch, либо объявляете метод (где он используется) для выдачи «Exception» самостоятельно.

Настоящая проблема - определение метода «шифровать». Ни один метод не должен возвращать «Exception», потому что он слишком универсальный и может скрывать некоторые другие виды исключений лучше иметь конкретное исключение.

Попробуйте это:

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.
  }

По сути, в этом конкретном случае вы должны убедиться, что пакет криптографии доступен в системе.

Java требуется расширение для пакета криптографии, поэтому исключения объявляются как «проверенные» исключения. Для вас справиться, когда их нет.

В этой небольшой программе вы ничего не можете сделать, если пакет криптографии недоступен, поэтому вы проверяете это во время «разработки». Если эти исключения генерируются во время работы вашей программы, это потому, что вы что-то сделали неправильно в «разработке», то подкласс RuntimeException является более подходящим.

Последняя строка больше не нуждается в выражении return, в первой версии вы перехватывали исключение и ничего не делали с ним, это неправильно.

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???

Если код не работает, лучше Fail fast

Вот несколько похожих ответов:

5 голосов
/ 26 мая 2009

Первая ошибка

java.lang.Exception; должен быть перехвачен или объявлен как брошенный байт [] encrypted = encrypt (concatURL);

означает, что ваш метод encrypt выдает исключение, которое не обрабатывается или не объявляется методом actionPerformed, в котором вы его вызываете. Прочитайте все об этом в Учебнике по исключениям Java .

У вас есть несколько вариантов выбора кода для компиляции.

  • Вы можете удалить throws Exception из вашего encrypt метода и фактически обработать исключение внутри encrypt.
  • Вы можете удалить блок try / catch из encrypt и добавить throws Exception и блок обработки исключений к вашему actionPerformed методу.

Обычно лучше обрабатывать исключение на самом низком уровне, чем вы можете, вместо того, чтобы передавать его на более высокий уровень.

Вторая ошибка просто означает, что вам нужно добавить оператор возврата в любой метод, содержащий строку 109 (в данном случае также encrypt). В методе есть оператор return, но если выдается исключение, оно может быть недоступно, поэтому вам нужно либо вернуться в блоке catch, либо удалить try / catch из encrypt, как я упоминал ранее. *

1 голос
/ 26 мая 2009

Вам нужно решить, как вы хотите обрабатывать исключения, выданные методом encrypt.

В настоящее время encrypt объявлено с throws Exception - однако в теле метода исключения перехватываются в блоке try / catch. Я рекомендую вам либо:

  • удалить предложение throws Exception из encrypt и обработать исключения внутренне ( рассмотрите возможность записи сообщения журнала как минимум ); или
  • удалите блок try / catch из тела encrypt и окружите вызов до encrypt вместо этого try / catch (т.е. в actionPerformed).

Относительно ошибки компиляции, на которую вы ссылаетесь: если в блоке try из encrypt было сгенерировано исключение, ничего не возвращается после завершения блока catch. Вы можете решить эту проблему, первоначально объявив возвращаемое значение как null:

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

Однако, если вы можете исправить большую проблему (стратегию обработки исключений), эта проблема сама по себе позаботится - особенно если вы выберете второй вариант, который я предложил.

0 голосов
/ 26 мая 2009

В вашем методе 'encrypt' вы должны либо избавиться от try / catch и вместо этого добавить try / catch вокруг того места, где вы вызываете encrypt (внутри 'actionPerformed'), либо вернуть null внутри catch в рамках encrypt (это второй ошибка.

0 голосов
/ 26 мая 2009

В actionPerformed(ActionEvent e) вы звоните encrypt(), который объявлен, чтобы бросить Exception. Тем не менее, actionPerformed не перехватывает это исключение (при попытке / перехватить вызов encrypt()) и не объявляет, что оно выбрасывает Exception.

Ваш encrypt метод, однако, на самом деле не выдает Exception. Он проглатывает все исключения, даже не регистрируя жалобы. (Плохая практика и плохой стиль!)

Кроме того, ваш метод encrypt выполняет следующие действия:

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
}

То есть, если вы перехватываете какое-либо Исключение, вы молча отбрасываете его, а затем падаете на дно вашего encrypt метода, фактически ничего не возвращая. Это не скомпилируется (как вы видите), потому что метод, объявленный для возврата значения, должен либо вернуть значение, либо выдать исключение для каждого возможного пути кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...