Не удается определить, что вызывает исключение NullPointer - PullRequest
2 голосов
/ 18 февраля 2010

У меня есть метод, который выглядит следующим образом:

try {
  doStuff();
} catch (Exception ex) {
  logger.error(ex);
}

(на самом деле я не использую имена методов, такие как doStuff - это просто для упрощения)

В doStuff я делаю множество вещей, среди которых есть вызов метода доступа к данным (так, еще один метод в doStuff), который заканчивается следующим:

} catch (SQLException ex) {
  logger.error(ex);
} finally {
  try {
    connection.close();
    proc.close();
    results.close();
  } catch (Exception e) {
    logger.error(e);
  } //<--Exception thrown here. HUH?
}
return stuff;

При переходе по этому коду я получаю вторую фигурную скобку (помеченную комментарием), а затем прыгаю вверх до зацепки в первом блоке кода с исключением NullPointer. results.close() - это то, что запускается прямо перед ним (результат не равен нулю). Моя среда IDE (NetBeans) не предоставляет трассировку стека (она показывает, что трассировка стека равна нулю) или любую другую информацию, кроме имени исключения (из того, что я могу сказать).

Ранее этот код работал нормально. Фактически, пока он работал, я изменил хранимую процедуру, которую вызывал метод доступа к данным (где я получаю это исключение), и затем эта ошибка начала возникать (без остановки приложения вообще). С тех пор я пытался восстановить и перезапустить, но безрезультатно. Я мог бы изменить sproc обратно, но я действительно хочу выяснить, из-за чего эта ошибка, поскольку не имеет смысла, что sproc даже будет частью этого, учитывая, где в коде происходит исключение.

Ответы [ 6 ]

3 голосов
/ 18 февраля 2010

ваш метод doStuff () генерирует что-то отличное от SQLException, и он не перехватывается.добавьте блок catch (Exception e) и зарегистрируйте это исключение и посмотрите, что произойдет.

этот пример кода демонстрирует то же поведение, которое вы описываете:

public class TryCatchTest {
    public static void main(String[] args) {
        try {
            System.out.println("foo");
            throw new NullPointerException();
        } finally {
            try {
                System.out.println("bar");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } // exception thrown here
    }
}
3 голосов
/ 18 февраля 2010

Закройте ресурсы в обратном порядке, в котором они были получены:

try 
{ 
    results.close(); 
    proc.close(); 
    connection.close(); 
} 
catch (Exception e) 
{ 
    logger.error(e); 
} //<--Exception thrown here. HUH? 

Я бы также порекомендовал такие методы:

public class DatabaseUtils
{
    // similar for ResultSet and Statement
    public static void close(Connection c)
    {
       try
       {
           if (c != null)
           {
               c.close();
           }
       }
       catch (SQLException e)
       {
           // log or print.
       }
    }
}
2 голосов
/ 18 февраля 2010

NullPointerException не может быть брошено в строку без оператора.

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

Редактировать: Как указывает emh, это может быть и исключение перед входом в блок finally.

2 голосов
/ 18 февраля 2010

Вполне может быть, что логгер нулевой.

Трудно точно определить исключения часто вызываются в самом обработчике исключений.

0 голосов
/ 18 февраля 2010

Как я сказал в комментарии, никогда не поймайте исключение, с которым вы не хотите иметь дело. В вашем коде, предполагая, что он завершен, вы не делаете ничего интересного за исключением, а это вызывает у вас путаницу в том, где и почему происходит исключение. Если вы действительно хотите сделать больше, чем log или printStackTrace(), например, обернуть его исключением, специфичным для домена (например, your.package.DataAccessException или чем-то еще), тогда отлично.

Сделайте что-нибудь еще, как это:


ResultSet results = null;
CallableStatement proc = null;
Connection connection = null;
try {
  connection = >
  proc = connection.createCallableStatement(..);
  results = proc.execute(..);
  >
} finally {
  try {
    if ( results != null ) {
      results.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
  try {
    if ( proc != null ) {
      proc.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
  try {
    if ( connection != null ) {
      connection.close();
    }
  } catch (Exception e) {
    logger.error(e);
  }
}

А потом в звонилке:


    try {
        doStuff();
    } catch ( SQLException e ) {
        throw new your.package.DataAccessException(e);
        // or just let the SQLException propagate upward
    } catch ( Exception e ) {
        throw new your.package.AppException("omg, crazy pills!", e);
        // or, once again, just let the exception
        //  propagate and don't catch anything
    }

Итак, вынос:

  1. не регистрируйте исключение, где они происходят, просто передавайте их, вложенные в другое исключение. Вы не хотите, чтобы ваш процесс не знал, успешно ли выполнено действие SQL или нет. Вы бы лучше остановились и занялись чем-то другим.
  2. Вложите исключения до тех пор, пока не доберетесь до конца строки, таким образом, у вас всегда будет полный след в том месте, где вы хотели обработать исключение, а не в пяти местах, разбросанных по журналу вашего сервера.
  3. Гнездо исключений (да, я говорил это дважды!), Чтобы вам было все равно, откуда JVM на самом деле выдает исключение, у вас есть следующее исключение, за которым нужно следовать, сообщая, что это на самом деле вызываемое утверждение или неправильное закрытие ваших ресурсов и т. д.
  4. Не вкладывайте и не выбрасывайте исключения из ошибок, обнаруженных в вашем коде finally, которые будут мешать исходному исключению и будут более интересными, чем невозможность закрытия и утверждение, которое не было открыто в первую очередь. .
  5. Установите переменные на null перед их использованием, а затем проверьте на нулевое значение перед close() их использованием.
  6. Поймайте каждую проблему в блоке finally по отдельности, так как вы, возможно, не сможете закрыть ваш ResultSet (потому что из-за какой-то ошибки выполнения он не открылся в первую очередь), но вам все равно следует попытаться закрыть CallableStatement и Connection, так как это, вероятно, не затронуто и все равно приведет к утечке ресурсов.

Надеюсь, это поможет.

0 голосов
/ 18 февраля 2010

Я на 99% уверен, что это происходит в драйвере JDBC. Для начала, ваши близкие заявления обратны. Вы должны закрыть набор результатов, оператор и соединение в указанном порядке.

Если вы работаете на сервере приложений, который управляет транзакциями, то попытка зафиксировать транзакцию может вызвать исключение внутри драйвера JDBC.

Это также может быть что-то о том, как наборы результатов генерируются в сохраненной процедуре, например, доступ к одному, затем доступ к другому, а затем возврат к первому.

...