写点什么

Groovy StringBuilder 类踩坑

作者:FunTester
  • 2023-12-06
    河北
  • 本文字数:1701 字

    阅读完需:约 6 分钟

今天在写脚本的时候发现一个奇怪的错误。经过猜想验证,发现原来 Groovy 过于灵活了,算是重复踩了之前的坑。Groovy 特性描述如下:


当 Groovy 脚本调用 getFun()和 setFun()方法时,会默认给这个类有一个 FunTester 的属性。反过来,如果这个类有 Fun 这个属性,那么 get 和 set 方法是不用显式写出来的。


本来这是个好事情,一方面其实可以免去多余代码,一方面更容易收拢入口方法(因为直接访问属性、修改属性也是有限调用 get 和 set 方法)。


但是就是这个特性让我下面的代码报错了。


        StringBuilder sb = new StringBuilder()        for (int i = 0; i < 3; i++) {            sb.append("a" + i)            output(sb.toString())            sb.setLength(0)        }
复制代码


其中 java.lang.AbstractStringBuilder#setLength 方法是用来裁剪 StringBuilder 对象内容的,如果参数为 0,实际的功效就是清空。


官方的描述为:


setLength(int newLength)AbstractStringBuilder 类中的一个方法,用于设置字符串的长度。具体来说,它有以下作用:


  • 如果 newLength 小于当前字符串的长度,则字符串将被截断为指定的长度 newLength

  • 如果 newLength 大于当前字符串的长度,则在字符串末尾填充空字符('\0')直到字符串达到指定的长度 newLength


下面是我代码报错信息:


No signature of method: java.lang.StringBuilder.setLength() is applicable for argument types: (Integer) values: [0]  at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:70)  at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)  at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)  at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)  at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
复制代码


错误信息显示并没有这个方法,真是见了鬼了,我在 Intellij 里面查看源码时明明显示没有问题。当我把问题抛给 ChatGPT,得到如下回答。


这个错误信息是 Groovy 中的一个问题,可能是因为 Groovy 与 Java 在StringBuilder类的操作上存在某些不同。setLength()方法通常用于设置StringBuilder的长度,但是错误信息表明setLength()方法似乎被错误地调用,传递了一个不正确的参数类型。在 Java 中,setLength()方法接受一个int类型的参数,表示要设置的新长度。但是在错误信息中显示传递了Integer类型的值 [0],这可能导致方法调用失败。如果问题仍然存在,可能需要进一步检查 Groovy 代码中的其他部分,以确保在StringBuilder操作方面没有其他的语法错误或问题。


这个时候我才意识到这是一个 Groovy 的报错,并不是 Java 的。所以,根据我多年踩坑经验早就的敏感度,set 方法一定是出问题了。经过我检查,StringBuilder 类并没有 length 属性,这就是导致报错的根本原因。


下面我来验证自己的猜想,通过 Groovy 元编程给 StringBuilder 类加上这个 length 属性。


        StringBuilder.metaClass.length= 32        StringBuilder sb = new StringBuilder()        for (int i = 0; i < 3; i++) {            sb.append("a" + i)            output(sb.toString())            sb.setLength(0)        }
复制代码


这下不报错了,但问题来了,setLength 功能不起作用了,因为优先去设置属性值去了。看来虽然验证了,但是功能破坏了,只好用点笨办法了。


        StringBuilder.metaClass.length= 32        StringBuilder sb = new StringBuilder()        for (int i = 0; i < 3; i++) {            sb.append("a" + i)            output(sb.toString())        }
复制代码


这个就解决了所有问题。当我去用 Java 代码中验证时,发现一直没有报错。我换了个项目(Maven/Gradle)结果发现居然无法复现了。哎,又遇到幽灵的问题,可能 Groovy 在编译这个项目类的时候开小差了。我的 JDK 版本 17,Groovy 编译插件版本 3.0.1,重新清空本地缓存重启 Intellij 也依然如此。通过对比两个项目差异,同时升级 Groovy 依赖版本和编译插件版本,改缺陷自动解决了。


发布于: 刚刚阅读数: 4
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
Groovy StringBuilder类踩坑_FunTester_InfoQ写作社区