【问题标题】:Groovy ArrayList getting confused for a StringGroovy ArrayList 对字符串感到困惑
【发布时间】:2015-03-13 23:01:38
【问题描述】:

我从这段代码中看到了一些令人困惑的行为。

def fileArrayMeta  = newFile.readLines()
def file3 = fileArrayMeta.collect{ line -> line.split("\\s+") }
println file3[0]
println file3[0].getClass()

这个操作的预期结果应该是。

=> [, NOTE, *ENTRY, STATEMENT, *.]
=> class java.util.ArrayList

这个操作的实际结果是。

=> [, NOTE, *ENTRY, STATEMENT, *.]
=> class [Ljava.lang.String;

为什么会这样?

println file3[0].removeAll("", null)

线程“主”groovy.lang.MissingMethodException 中的异常:没有方法签名:[Ljava.lang.String;.removeAll() 适用于参数类型: (java.lang.String, null) 值:[, null]

我认为这也应该有效,为什么不呢?

def clean4 = clean3.each{it.collect{ it != "" && it != null }}
    println clean4[0]

【问题讨论】:

  • L[] 是一个原生数组,它没有removeAll。而且你不能用每个来收集!。
  • 如果你想拥有所有非空/非空元素,那么只需使用findAll。例如assert ['a',null,''].findAll() == ['a'],因为 groovy-truth 摆脱了它们。 each 只返回原始列表,您的 collect 调用是无操作的。

标签: java arrays string file groovy


【解决方案1】:

java.lang.String 上的 split 方法返回一个数组,而不是 ArrayList。您可以改用 tokenize 方法(尽管它不需要正则表达式,这对于在空格上拆分的简单情况来说不是问题),或者在拆分后将数组转换为列表,使用 Arrays.asList 或 as List.

在 Groovy 中,拆分和标记化都默认使用空格作为分隔符,因此不需要正则表达式,line.split() as Listline.tokenize() 就足够了。制表符和空格都得到处理,重复的工作方式类似:

groovy:000> s = '  a\tb   c d '
===>   a        b   c d
groovy:000> s.tokenize()
===> [a, b, c, d]
groovy:000> s.split() as List
===> [a, b, c, d]

输出[Ljava.lang.Stringa notation telling you you have an array of Strings。您可以通过在类上调用 isArray() 来检查某物是否为数组:

file3[0].class.isArray()

MissingMethodException 表示您正在对数组调用 removeAll。您可以检查对象上可用的方法:

groovy:000> a = s.split()
===> [a, b, c, d]
groovy:000> a.class.isArray()
===> true
groovy:000> a.class.methods
===> [public final void java.lang.Object.wait(long,int) throws java.lang.Interru
ptedException, public final native void java.lang.Object.wait(long) throws java.
lang.InterruptedException, public final void java.lang.Object.wait() throws java
.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Obj
ect), public java.lang.String java.lang.Object.toString(), public native int jav
a.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.g
etClass(), public final native void java.lang.Object.notify(), public final nati
ve void java.lang.Object.notifyAll()]
groovy:000> a.class.methods*.toString().grep {it.contains('removeAll')}
===> []

你希望最后一个例子做什么?因为 collect 的调用会返回一个布尔值列表:

groovy> stuff=['asdf', 'zxcv', 'qwerty', '', 'zzz'] 
groovy> stuff.collect { it != '' && it != null } 

Result: [true, true, true, false, true]

collect 方法为调用它的集合创建一个转换后的副本。但是 each 不返回修改后的集合,它返回原始未修改的集合,这是一个示例:

groovy> def mylist = ['asdf', 'zxcv', 'qwerty'] 
groovy> def foo = mylist.each {it.toUpperCase()} 
groovy> foo 

Result: [asdf, zxcv, qwerty]

这里 each 中的闭包对 mylist 或 foo 的内容没有影响,这与您使用 collect 或 mylist*.toUpperCase() 不同,后者返回通过对 mylist 的每个元素执行闭包创建的条目集合。

您似乎对 collect 的作用感到困惑,并且尝试使用它进行过滤(这不起作用)。这是从字符串列表中删除空字符串的示例:

groovy> def mylist = [['a', 'b', ''], ['', 'c', 'd'], ['e', '', 'f']] 
groovy> println mylist.collect {it.findAll()} 

[[a, b], [c, d], [e, f]]

调用 findAll 的 it 是一个字符串列表。

【讨论】:

  • @kschmit90:getClass 返回以 [L 开头的东西,这意味着它是一个数组。您在问题中的输出告诉您这是一个字符串类型的数组。
  • [Ljava.lang.String 表示字符串数组。 [ 符号表示此
  • @kschmit90:你能在问题中添加一个例子吗?
  • @kschmit90:看起来您正试图在没有该方法的数组上调用 ArrayList 方法 removeAll。
  • @kschmit90:问题底部的示例不完整(未指定 clean3 的内容)并且未指定错误是什么。它似乎也与原始问题无关。
【解决方案2】:

你也可以使用line.split( /\s+/ ) as List

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 2020-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多