Scala 的 Collectors.groupingBy() 替代方案
Alternative to Collectors.groupingBy() for scala
在 Java 我有类似的东西:
Collectors.groupingBy((Re r) -> return r.pName)
而且它工作正常。现在我正在尝试将相同的东西放入 scala 中,例如:
Collectors.groupingBy((r:Re) => return r.pName)
但后来我得到了像
这样的东西
cannot resolve reference groupingBy with such signature
cannot resolve symbol groupingBy
unspecified value parameters Collector
unspecified value parameters Supplier
如果您还需要,请告诉我 info/code,我将创建一些虚拟示例,因为我不允许 post 确切的代码。
更新 基于@Vladimir Matveev 回答:
pName 应该是字符串,但是如果我写 new java.util.function.Function[Re, java.lang.String]
那么我会得到一个
type mismatch;
found : java.util.function.Function[Re,String]
required: java.util.function.Function[_ >: Re, _ <: ?0(in value x)(in value x)(in value x)(in value x)]
Java lambda 是 "implementors" 任意函数接口(在这种特殊情况下 Collectors.groupingBy()
接受 java.util.function.Function
。然而,Scala 匿名函数是某些 class 实现 scala.FunctionX
特征。因此,您不能将 Scala 函数用于任意函数接口(但据我所知,有计划允许这样做)。
您需要创建一个匿名 class 显式扩展 java.util.function.Function
:
Collectors.groupingBy(new java.util.function.Function[Re, ???] {
def apply(r: Re) = r.pName
})
(当然,您需要输入正确的 pName
类型而不是 ???
。
如果您经常这样做,您可以为 Scala 的 T => U
定义一个隐式转换为 java.util.function.Function[T, U]
:
implicit class FunctionWrapper[T, U](f: T => U) extends java.util.function.Function[T, U] {
def apply(x: T): U = f(x)
}
然后(假定此隐式在范围内)您可以像最初尝试的那样使用它:
Collectors.groupingBy((r: Re) => r.pName)
Update 我不知道为什么会发生错误(可能是因为 Scala 和 Java 泛型之间存在一些不兼容性),但是如果您明确指定所有类型,它就会发生工作:
scala> Collectors.groupingBy[Re, String](new JFunction[Re, String] {
| def apply(r: Re) = r.pName
| })
res2: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl@4f83df68
(JFunction
是 java.util.function.Function
的别名)。
带有隐式适配器的变体看起来更好(但仍然需要显式类型注释):
scala> Collectors.groupingBy[Re, String]((r: Re) => r.pName)
res4: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl@71075444
在 Java 我有类似的东西:
Collectors.groupingBy((Re r) -> return r.pName)
而且它工作正常。现在我正在尝试将相同的东西放入 scala 中,例如:
Collectors.groupingBy((r:Re) => return r.pName)
但后来我得到了像
这样的东西cannot resolve reference groupingBy with such signature
cannot resolve symbol groupingBy
unspecified value parameters Collector
unspecified value parameters Supplier
如果您还需要,请告诉我 info/code,我将创建一些虚拟示例,因为我不允许 post 确切的代码。
更新 基于@Vladimir Matveev 回答:
pName 应该是字符串,但是如果我写 new java.util.function.Function[Re, java.lang.String]
那么我会得到一个
type mismatch;
found : java.util.function.Function[Re,String]
required: java.util.function.Function[_ >: Re, _ <: ?0(in value x)(in value x)(in value x)(in value x)]
Java lambda 是 "implementors" 任意函数接口(在这种特殊情况下 Collectors.groupingBy()
接受 java.util.function.Function
。然而,Scala 匿名函数是某些 class 实现 scala.FunctionX
特征。因此,您不能将 Scala 函数用于任意函数接口(但据我所知,有计划允许这样做)。
您需要创建一个匿名 class 显式扩展 java.util.function.Function
:
Collectors.groupingBy(new java.util.function.Function[Re, ???] {
def apply(r: Re) = r.pName
})
(当然,您需要输入正确的 pName
类型而不是 ???
。
如果您经常这样做,您可以为 Scala 的 T => U
定义一个隐式转换为 java.util.function.Function[T, U]
:
implicit class FunctionWrapper[T, U](f: T => U) extends java.util.function.Function[T, U] {
def apply(x: T): U = f(x)
}
然后(假定此隐式在范围内)您可以像最初尝试的那样使用它:
Collectors.groupingBy((r: Re) => r.pName)
Update 我不知道为什么会发生错误(可能是因为 Scala 和 Java 泛型之间存在一些不兼容性),但是如果您明确指定所有类型,它就会发生工作:
scala> Collectors.groupingBy[Re, String](new JFunction[Re, String] {
| def apply(r: Re) = r.pName
| })
res2: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl@4f83df68
(JFunction
是 java.util.function.Function
的别名)。
带有隐式适配器的变体看起来更好(但仍然需要显式类型注释):
scala> Collectors.groupingBy[Re, String]((r: Re) => r.pName)
res4: java.util.stream.Collector[Re, _, java.util.Map[String,java.util.List[Re]]] = java.util.stream.Collectors$CollectorImpl@71075444