【问题标题】:Clojure: nullpointerexception with recursionClojure:带有递归的空指针异常
【发布时间】:2015-01-23 21:06:11
【问题描述】:

我正在创建一个以数字列表作为参数的重载函数(以及重载签名中的数字列表和单个数字)。必须从此列表中找到并返回最高值。我知道可用的“排序”方法会自动为您排序列表,但我正在尝试使用递归来发现最高值。下面是我正在使用的代码。

32    (defn my-max
33      ([list]
34        (if (empty? list)
35          -1
36          (my-max (pop list) (first list))) ; recursive call
37        )
38      ([list high]
39        (if (empty? list) ; base case
40          high)
41        (if (> (first list) high)
42          (my-max (pop list) (first list)))
43        (my-max (pop list) high))
44      )
45    
46    (println (my-max '(1 2 3)))

如您所见,我已经硬编码了一个包含 1、2 和 3 的列表,应该返回 3。运行代码时出现错误:

Exception in thread "main" java.lang.NullPointerException
    at clojure.lang.Numbers.ops(Numbers.java:942)
    at clojure.lang.Numbers.gt(Numbers.java:227)
    at user$my_max.invoke(HelloWorld.clj:41)
    at user$my_max.invoke(HelloWorld.clj:42)
    at user$my_max.invoke(HelloWorld.clj:42)
    at user$my_max.invoke(HelloWorld.clj:36)
    at user$eval2.invoke(HelloWorld.clj:46)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.load(Compiler.java:7064)
    at clojure.lang.Compiler.loadFile(Compiler.java:7020)
    at clojure.main$load_script.invoke(main.clj:294)
    at clojure.main$script_opt.invoke(main.clj:356)
    at clojure.main$main.doInvoke(main.clj:440)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:415)
    at clojure.lang.AFn.applyToHelper(AFn.java:161)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.main.main(main.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

此错误发生在最终递归调用中,其中 3 已从列表中“弹出”并作为“高”传递回 my-max,列表为空并且:

(if (empty? list) ; line 39, base case

应该评估为真,但评估为假。您对这个问题有什么想法/解决方案吗?

【问题讨论】:

  • Arthur Ulfeldt 的回答指出括号放错了位置。 Diego Basch 的回答澄清了这个问题是如何导致空指针异常的。我只是想指出,注意正确的自动缩进(您问题中的代码说明了这一点),可以立即看出括号有问题,因为表达式应该是 else 子句的缩进与最初的(if 完全相同。
  • 既然您提到 sort 作为在数字列表中查找最大值的一种方法(效率不高),请注意 clojure.core 中的 max

标签: recursion clojure nullpointerexception


【解决方案1】:

该语句(第 39-40 行)什么也没做。无论它评估为什么(highnil),都不会使用该值。然后第 41 行计算,如果您的列表为空,(first list) 为 nil,因此出现空指针异常。

【讨论】:

  • 除了使用正确的代码缩进很重要(我推荐一个支持使用 s-exp 和平衡括号等的编辑器),还应该注意你应该使用 recur 而不是不仅仅是递归调用你的过程,因为 Clojure 没有尾调用优化。 Recur 将确保此函数适用于即使是当前版本会很快耗尽堆栈的大型列表
【解决方案2】:

< 函数只能比较数字,因此一个非常直接的方法是使用 or 来确保它们是数字。第二个和第三个 if 语句的结尾 ) 也在错误的位置。

user> (defn my-max
       ([list]
         (if (empty? list)
          -1
           (my-max (pop list) (first list))))

       ([list high]
        (if (empty? list) ; base case
          high
         (if (> (or (first list) 0) (or high 0))
            (my-max (pop list) (first list))
            (my-max (pop list) high)))))
      #'user/my-max
      user> (println (my-max '(1 2 3)))
      3
      nil

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 2012-06-13
    相关资源
    最近更新 更多