【问题标题】:In Intellij, how can I throw an exception at a break point?在 Intellij 中,如何在断点处引发异常?
【发布时间】:2013-06-13 18:22:30
【问题描述】:

我看到很多关于如何让 Intellij 打破异常的问题。我正在尝试做一些不同的事情:我想在断点处抛出一个异常,以便我可以看到如果在该代码处发生异常会发生什么。

我已经找到了强制执行此操作的方法。例如,如果我有一个名为willBeUsed 的变量,我可以打断点并添加一个显示willBeUsed = null 的手表。这将触发 NullPointerException 最终

但我现在想发送IOException 看看会发生什么。没有办法欺骗我的代码这样做。当我添加一块写着throw new IOException() 的手表时,它给了我一个错误,说“意外的令牌”。

作为一种解决方法,我可以修改代码以引发异常并重新部署。但我想知道是否有办法在调试器中执行此操作而无需修改源代码。

【问题讨论】:

  • 不太可能有办法按照您的要求进行操作。我建议研究一种更容易促进这种测试的不同设计——例如dependency injection
  • @RobI 依赖注入很好。我看不出它对我有什么帮助。你能详细说明一下吗?
  • 简短的想法:创建一个接口来执行您在有时会引发异常的代码块中所做的事情(例如,IODoerdo() 方法)。您真正的实现是在一个具体类IODoerImpl 中,包含所有真实代码,但您有另一个具体类TestIODoer,每次调用它的do() 方法时,或每隔一次或任何时候都会引发异常。 .. 通常你的程序使用真正的实现,但是在测试期间你可以注入这个测试类来代替。

标签: java intellij-idea


【解决方案1】:

您可以右键单击堆栈跟踪并选择“抛出异常”

(自 2018.1 版本开始。请参阅 JetBrains 问题:IDEA-148408

【讨论】:

  • 怎么做?请添加一些屏幕截图。
  • @BreakingBenjamin 您可以右键单击堆栈跟踪并选择“抛出异常”。 mbaranauskas 的回答附有截图。
  • 这个选项在菜单下运行->抛出异常也有,调试的时候可以点击。
  • 对我来说,今天花了几个小时搜索错误,但有一个解决方案。 错误描述:当我使用 swing java 应用程序时以这种方式抛出异常,它第一次被正确触发(我跟踪它),但之后应用程序的行为不正确:我无法启动新的 IProgressWorker 作业。 解决方案: stackoverflow.com/a/17094415/3895476 的方法有效。
【解决方案2】:

如何将throw 语句放在if 块中,并且只更改条件,例如:

boolean shouldThrowException = false;
// ....
if ( shouldThrowException ) //place breakpoint here
{
    throw new IOException();
}

当您遇到断点时,将shouldThrowException 的值更改为true。

【讨论】:

  • 我几乎已经在我的问题中给出了这个作为解决方法。但如果这是唯一的方法,我想这是唯一的方法。
  • 对不起,我一定是在你的问题中错过了它,很抱歉没有提供太多帮助..
【解决方案3】:

在“调试器”窗口的“框架”部分中,右键单击当前函数并选择“抛出异常”。然后输入你要抛出的异常。

【讨论】:

    【解决方案4】:

    我看不出这是怎么做到的。我尝试了两种方法(也许我的想法会引出一些其他的想法

    1) 我尝试使用调试器“记录评估表达式”到throw new IOException(),但我得到的只是 IDEA 无法评估表达式的消息。

    2) 我也尝试设置一个断点,当它停止时,我打开“评估表达式”对话框抛出一个新异常,但这也不起作用。

    我不认为调试器可以抛出异常。 @Binyamin 的解决方案将起作用,但您已经在问题中提到了这一点。我只能在 IDEA 中添加,可以取消选中“暂停”复选框并在“日志评估表达式”框中输入 shouldThrowException = true。这将导致调试器仅更改值(并记录它)但不会停止,这在具有许多并发线程的代码中非常有用。

    【讨论】:

      【解决方案5】:

      我不知道您是否尝试过,但您或许可以创建一个仅抛出 IOException 的静态方法,然后通过发出 Evaluate Expression 调用该方法。

      简单示例代码:

      package com.stackoverflow;
      
      import java.io.IOException;
      
      public class Main {
          public static void main(String[] args) {
      
              doStuff();
          }
      
          private static void throwException() throws IOException {
              throw new IOException();
          }
      
          private static void doStuff() {
              System.out.println("doStuff");
          }
      }
      

      System.out.println 行设置断点:

      打开Evaluate Expression... 窗口并调用throwException 方法(评估),然后您将从doStuff 中获得堆栈跟踪:

      当然会在throwException 中出现异常,但您也会看到整个调用堆栈。

      【讨论】:

      • 是的,那行得通。但我仍然必须重新部署。但是,最好把它放在一个库中,然后我可以在任何项目需要时调用它。这样我就不需要修改主项目中的任何源文件或重新部署。我可以使用 maven 范围,这样我打包时就不会部署它。
      • @tieTYT 是的,这正是我的想法。
      • 我试过了,控制台的输出没有显示异常。我认为它会在自己的实例中评估异常,因此不会影响主线程。
      • @tieTYT IOException 的问题在于它是一个检查异常,因此所有方法都必须声明一个 throws IOException。如果你想在一个没有声明的方法中突然从调试器抛出 IOException,会发生什么?
      • 虽然这是一个好点,1) 如果我的源代码确实发生了抛出 IOException,那么问题仍然存在 2) 如果我的 throwException 方法抛出了 RuntimeException,我的问题仍然会发生,如我的评论中所述.所以这不是测试如果在断点处抛出异常会发生什么的方法。
      【解决方案6】:

      还有另一种方式可以利用 JVM HotSwapping。

      假设您正在将代码部署到某个服务器。然后,当您启动应用程序时,请确保您打开远程调试(我认为您在调试并且正在谈论部署时已经打开了)。如果不是,那么它将在本地调试器中正常工作。

      现在我有两个类,Main 和 Other。

      package com.stackoverflow;
      
      import java.io.IOException;
      
      public class Main {
          public static void main(String[] args) throws IOException {
              doStuff();
          }
      
          private static void doStuff() throws IOException {
              System.out.println("doStuff");
              Other.otherStuff();
          }
      
          public static void throwException() throws IOException {
              throw new IOException();
          }
      }
      


      package com.stackoverflow;
      
      import java.io.File;
      import java.io.IOException;
      
      public class Other {
          public static void otherStuff() throws IOException {
              File file = new File("Some_File.txt");
              file.createNewFile();
          }
      }
      

      throwException() 可以放在任何地方,只要它“全局”可用,例如在某些实用程序类中。现在它只是为了方便放在我的 Main 类中。

      现在我们可以在我们的doStuff() 方法中设置一个断点,并在保留在那里的同时更改otherStuff() 方法中的代码,以便它调用我们的静态throwException() 方法。

      public static void otherStuff() throws IOException {
          Main.throwException();
          File file = new File("Some_File.txt");
          file.createNewFile();
      }
      

      我们必须调用一些方法而不是调用throw new IOException(),否则Unreachable statement 会出错。

      然后我们可以按Ctrl+Shift+F9重新编译Other类。现在它将是 HotSwapped(一个对话框将询问您是否真的要这样做)。

      然后按继续,就会抛出异常。

      然后代码可以恢复到正常状态。

      这样做的好处是重新编译的类甚至可以“通过网络”热交换到远程机器。

      重要的是你重新编译的代码必须在另一个类中。您有断点的同一个类将无法正确重新加载。

      作为一种解决方法,我可以修改代码以引发异常并重新部署。但我想知道是否有办法在调试器中执行此操作而无需修改源代码。

      您将在调试器中修改代码,但只能在您需要的时候进行。然后,您可以恢复小更改并重新编译以热交换回旧代码。

      我希望你能理解(不是双关语)。

      如果你愿意,我可以添加屏幕截图。

      【讨论】:

      • 好吧,这可能行得通。根据我的经验,HotSwapping 有 30% 的时间可以正常工作,但这可能没问题。谢谢
      • @tieTYT 希望它能在 30% 以上的时间内为您工作。我现在没有想法,这是我能想到的最好的:-)
      猜你喜欢
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 2013-02-05
      • 2014-06-13
      • 2019-01-28
      • 2020-09-02
      • 2011-09-18
      • 1970-01-01
      相关资源
      最近更新 更多