почему нельзя объявить класс исключения throw?

#java

#java

Вопрос:

 package com.csl.bps.util;

import java.awt.Event;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;

import javax.servlet.ServletContextEvent;

public class Reloader implements Runnable{
    private boolean firstLoad = true;
    private ServletContextEvent eventCopy = null;
    private File configFile = null;
    private String configFilePath = null;
    private HashMap map = null;
    private BufferedReader reader = null;
    private long lastModifiedTime = 0;
    public Reloader(ServletContextEvent event) {
        eventCopy = event;
        //event.getServletContext().setAttribute("i", new Integer(2));
    }

    public void run() {
        configFilePath = (String)eventCopy.getServletContext().getInitParameter("billRunDetailConfig");
        if(configFilePath == null)
        {
            eventCopy.getServletContext().log("Warning: No bill run detail config file found. Please check the file and restart.");
        }
        configFile = new File(configFilePath);
        if(firstLoad == true)
        {
            map = createMap(configFile);
            lastModifiedTime = configFile.lastModified();
            eventCopy.getServletContext().setAttribute("BunRunDetail", map);
            eventCopy.getServletContext().log("nnFirst load of bill run detail config file. HashMap loaded.n");
            firstLoad = false;
        }
        else
        {
            eventCopy.getServletContext().log("nnAnother load of bill run detail config file. Checking for the file's last modified time...n");
            if(configFile.lastModified() != lastModifiedTime)
            {
                map = createMap(configFile);
                lastModifiedTime = configFile.lastModified();
                eventCopy.getServletContext().setAttribute("BunRunDetail", map);
                eventCopy.getServletContext().log("Config file changed. HashMap is hashed again.");
            }else
            {   
                eventCopy.getServletContext().log("Config file is not changed.");
            }
        }
    }

    private HashMap createMap(File configFile){
        HashMap map = null;
        try{
            reader = new BufferedReader(new FileReader(configFile));
        }catch(FileNotFoundException ex){
            ex.printStackTrace();
        }
        return map;
    }
}
  

Я хотел бы создать любое исключение для вызывающего любого метода, но я не могу, например:
Я могу это сделать:

 private HashMap createMap(File configFile) throws FileNotFoundException{
    HashMap map = null;
    try{
        reader = new BufferedReader(new FileReader(configFile));
    }catch(FileNotFoundException ex){
        //ex.printStackTrace();
        throw ex;
    }
    return map;
}
  

Но в приведенном выше:

 if(firstLoad == true)
{
    map = createMap(configFile);
    lastModifiedTime = configFile.lastModified();
    eventCopy.getServletContext().setAttribute("BunRunDetail", map);
    eventCopy.getServletContext().log("nnFirst load of bill run detail config file. HashMap loaded.n");
    firstLoad = false;
}
  

Здесь, в строке map = createMap(configFile) я получил ошибку запроса в eclipse для не обработанного исключения, но я могу только добавить к нему предложение try catch.

Я бы хотел, чтобы он выдавал исключение своему вызывающему объекту и позволял вызывающему объекту обрабатывать исключение, потому что, если я вернусь сюда, я не уверен, что все ресурсы закрыты.


Почему его подпись не содержит предложения throws? Предполагается ли, что он не создаст никакого исключения?

Если появится исключение, и я оберну его предложением try / catch, остановится ли поток и уведомит ли он родительский?

Ответ №1:

Причина, по которой вы не можете добавить предложение «throws» к методу run(), заключается в том, что run() определен в интерфейсе Runnable, и его подпись не содержит предложения throws.

Комментарии:

1. Я знаю это, но почему его подпись не содержит предложения throws? Предполагается ли, что он не создаст никакого исключения?

2. Runnable — это очень универсальный интерфейс; любые проверенные исключения, которые он может выдавать, слишком многочисленны, чтобы перечислять (поскольку вы можете поместить в него что угодно), поэтому он просто не перечисляет ни одного и ожидает, что run () обработает проверенные исключения и, возможно, выдаст непроверенные исключения и ошибки.

Ответ №2:

Вы не должны добавлять какие-либо проверенные исключения в объявление. Причина просто в том, что интерфейс, который можно запустить, не объявляя исключение, обещает, что оно не будет выдано никаким Runnable.

Я бы хотел, чтобы он выдавал исключение своему вызывающему объекту и позволял вызывающему объекту обрабатывать исключение, потому что, если я вернусь сюда, я не уверен, что все ресурсы закрыты.

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

 try {
    ...
} catch (FileNotFoundException e) {
    throw new MyRuntimeFileNotFoundException(e);
}
  

Таким образом, вы рискуете забыть перехватить его позже (поскольку он не объявлен). Но иногда это необходимо. Конечно, вы можете использовать simply throw new RuntimeException(e) вместо своего собственного.

Комментарии:

1. 1 за то, что он (намного, намного) более точный. хотя у меня все еще есть сомнения по поводу необходимости перехвата исключения из run в большинстве случаев.

2. @MByD согласен, в большинстве случаев вам это не нужно. Однажды мне пришлось обернуть один Runnable в другой и перехватить исключение, чтобы я мог зарегистрировать его и выполнить некоторую очистку. Возможно, это можно было бы сделать по-другому.

3. Я не понимаю…… Если я не могу добавить к нему объявление throw, как я могу его создать? И если я не могу его создать, есть ли у нас способ сообщить вызывающему «произошло что-то неправильное»?

4. Ого, я могу обернуть исключение в исключение во время выполнения? Это намного удобнее.

5. Действительно, это называется переносом исключений или цепочкой .

Ответ №3:

Когда вы переопределяете метод, реализуете метод интерфейса или реализуете абстрактный метод, вы переопределяете его методом с точной сигнатурой, которая включает в себя имя, типы параметров и порядок, броски (РЕДАКТИРОВАТЬ, как указано maaartinus, это относится только к проверяемым исключениям) (если существует) и возвращаемый тип. Если вы хотите реализовать Runnable, вы должны реализовать метод run Runnable интерфейса. Сигнатура этого метода не содержит никаких throw , поэтому вы не переопределяете его своим методом.

Более того, хотя вы можете объявить два метода с одинаковым именем, но с разными аргументами, такими как:

 public int foo(int i);
  

и

 public int foo(String s);
  

Вы не можете объявить два метода с одинаковым именем и параметрами, которые отличаются только тем, что они выдают (РЕДАКТИРОВАТЬ, как указано maaartinus, это относится только к проверяемым исключениям) или что они возвращают. например, вы не можете объявить два из трех методов одновременно:

 public int foo();
public boolean foo();
public boolean foo() throws FileNotFoundException;
  

public boolean foo() вызывает исключение FileNotFoundException;

Поскольку вы реализуете, Runnable вы должны реализовать public void run() , и вы не можете реализовать public void run() throws FileNotFoundException .

Комментарии:

1. На самом деле, вы совершенно не правы. При реализации Closeable вы можете реализовать либо void close() throws IOException , либо просто void close() . Даже void close() throws NullPointerException это нормально. Вы просто не должны добавлять никаких проверенных исключений, вот и все.