【问题标题】:Why Intellij's debugger hits breakpoint twice for this Scala code为什么 Intellij 的调试器会为此 Scala 代码两次命中断点
【发布时间】:2022-01-14 16:42:06
【问题描述】:

当我在 if 语句中设置调试点并启用“日志:断点命中消息”时,用于以下 scala 代码

object App1 {
  def main(args: Array[String]): Unit = {
    iftest()
  }
  def iftest(): Unit = {
    val setA: Set[String] = Set("a", "b", "c");
    var setB: Set[String] = Set("d", "e", "f")
    if(setA.size > setB.size){ //here break point at line 8
      println("bigger")
    }
  }
}

我在控制台中得到以下输出。问题是为什么这个断点会被命中两次?

Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)
Breakpoint reached at com.eguller.App1$.iftest(App1.scala:8)

但是对于类似的Java代码,断点只被命中一次。

        Set<String> set1 = new HashSet<>();
        set1.add("1");
        set1.add("2");

        Set<String> set2 = new HashSet<>();
        set2.add("a");
        set2.add("b");

        if(set1.size() > set2.size()){ //here break point at line 8
            System.out.println("size different");
        }

我得到以下输出

Breakpoint reached at com.eguller.JApp.main(JApp.java:8)

这是 Intellij 调试器中的错误,还是 Scala 编程语言的一个特性?

IntelliJ IDEA 2021.3 爪哇 - 11 斯卡拉 - 2.12.15

【问题讨论】:

    标签: java scala debugging intellij-idea breakpoints


    【解决方案1】:

    这是 scalac 字节码生成的一个特点。由于某种原因,它在返回指令之前为调试器生成了一个额外的位置并将其放在该行上。您可以在 IDE 中调用“显示字节码”操作并看到有 2 个LINENUMBER 8 条目:

    // access flags 0x1
    public iftest()V
     L0
      LINENUMBER 6 L0
      GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
      INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
      GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
      ICONST_3
      ANEWARRAY java/lang/String
      DUP
      ICONST_0
      LDC "a"
      AASTORE
      DUP
      ICONST_1
      LDC "b"
      AASTORE
      DUP
      ICONST_2
      LDC "c"
      AASTORE
      CHECKCAST [Ljava/lang/Object;
      INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
      INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
      CHECKCAST scala/collection/immutable/Set
      ASTORE 1
     L1
      LINENUMBER 7 L1
      GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
      INVOKEVIRTUAL scala/Predef$.Set ()Lscala/collection/immutable/Set$;
      GETSTATIC scala/runtime/ScalaRunTime$.MODULE$ : Lscala/runtime/ScalaRunTime$;
      ICONST_3
      ANEWARRAY java/lang/String
      DUP
      ICONST_0
      LDC "d"
      AASTORE
      DUP
      ICONST_1
      LDC "e"
      AASTORE
      DUP
      ICONST_2
      LDC "f"
      AASTORE
      CHECKCAST [Ljava/lang/Object;
      INVOKEVIRTUAL scala/runtime/ScalaRunTime$.wrapRefArray ([Ljava/lang/Object;)Lscala/collection/immutable/ArraySeq;
      INVOKEVIRTUAL scala/collection/immutable/Set$.apply (Lscala/collection/immutable/Seq;)Ljava/lang/Object;
      CHECKCAST scala/collection/immutable/Set
      ASTORE 2
     L2
      LINENUMBER 8 L2
      ALOAD 1
      INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
      ALOAD 2
      INVOKEINTERFACE scala/collection/immutable/Set.size ()I (itf)
      IF_ICMPLE L3
     L4
      LINENUMBER 9 L4
      GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
      LDC "bigger"
      INVOKEVIRTUAL scala/Predef$.println (Ljava/lang/Object;)V
      GOTO L3
     L3
      LINENUMBER 8 L3
     FRAME APPEND [scala/collection/immutable/Set scala/collection/immutable/Set]
      RETURN
     L5
      LOCALVARIABLE setA Lscala/collection/immutable/Set; L1 L3 1
      LOCALVARIABLE setB Lscala/collection/immutable/Set; L2 L3 2
      LOCALVARIABLE this LApp1$; L0 L5 0
      MAXSTACK = 6
      MAXLOCALS = 3
    

    Scala 3 编译器没有添加这个并且断点按预期工作。

    【讨论】:

    • 感谢@niktrop,我正在调试一个 Scala 代码,其中包含理解/收益、期货等。我认为我的代码被调用了两次并试图找出根本原因。最终我怀疑,也许代码没有执行两次,但断点多次命中并以简单的方法进行测试。确实是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2012-09-12
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多