2011-05-13 15 views
2

我刚刚开始在scala中,我将一些java代码转换为scala并试图使它更好,功能更优雅。在功能上在scala中包含一组对象中的集合

我有以下代码包含一个方法(getRequiredUploadPathKeys),它给出了MyClass中所有可用路径模板所需的所有路径键的联合。

trait PathTemplate { 
    def getRequiredPathKeys:Set[PathKey] 
} 

class MyClass(accessPaths:Set[PathTemplate], targetPath:PathTemplate){ 

    def getAllRequiredPathKeys: Set[PathKey] = { 
     val pathKeys = HashSet[PathKey]() 
     pathKeys.addAll(targetPath.getRequiredPathKeys) 

     for (accessTemp <- accessPaths) { 
      pathKeys.addAll(accessTemp.getRequiredPathKeys) 
     } 
     return pathKeys 
    } 
} 

这个方法就好像它可以在scala中更加简洁。任何人都可以指出我如何获得它?

感谢, 保罗

回答

4

你的意思是这样的:

def getAllRequiredPathKeys = (accessPaths map { _.getRequiredPathKeys }).flatten ++ targetPath.getRequiredPathKeys 
+3

你可以使用flatMap使它更短。 – 2011-05-13 11:54:12

+0

真棒谢谢:)我已经非常接近,但平坦的方法是失踪的位! – Paul 2011-05-13 12:29:57

6
def getAllRequiredPathKeys = 
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 

或者与

def getAllRequiredPathKeys = 
    for(path <- accessPaths + targetPath; 
     key <- path.getRequiredPathKeys) yield key 
6

这里的奇怪的事情是,你正在使用Java的HashSet - 没有012 Scala中的- 而且没有必要。

因此,我要评论各种设计决策以及它们与Java到Scala的不同之处。首先,

val pathKeys = HashSet[PathKey]() 

自定义Scala通常不会引用实现接口的类,因为接口有一个工厂。所以你通常只使用Set[PathKey]()。此外,这显然是一个斯卡拉工厂,因为没有new关键字 - 这意味着其他代码将无法正常工作,因为Scala的Set中没有addAll

pathKeys.addAll(targetPath.getRequiredPathKeys) 

在这里,您不使用targetPath.getRequiredPathKeys直接因为Java的Set是可变的。默认的Scala Set是不可变的,这使得它无用 - 您可以使用targetPath.getRequirePathKeys作为基本集合,而不必将其元素添加到另一个集合。

性能方面,斯卡拉般的功能语言 - 在其不可变集合实现中使用persistent datastructures。这意味着它会重用一个数据结构的一部分来创建派生数据结构,而不是在每次创建新数据结构时都复制所有内容。这是唯一可能的,因为不变性保证。

在任何情况下,你可能只是这样做:

val pathKeys = targetPath.getRequiredPathKeys 

接下来,

for (accessTemp <- accessPaths) { 
     pathKeys.addAll(accessTemp.getRequiredPathKeys) 
    } 

首先,推导的习惯用法是返回一个值,即,对于收益。上面的使用应该仅限于代码的副作用部分。为了更清楚,上面可以分两个步骤来完成:

// Get all required Path Keys 
    val requiredPathKeys = for { 
     accessPath <- accessPaths 
     requiredPathKey <- accessPath.getRequiredPathKeys 
    } yield requiredPathKey 

    // Then add them 
    pathKeys.addAll(requiredPathKeys) 

然而,由于你不addAll东西Scala的Set,你要么需要做pathKeys一个var,或使用可变数据结构,或简单地改变的顺序:

val requiredPathKeys = for { 
     accessPath <- accessPaths 
     requiredPathKey <- accessPath.getRequiredPathKeys 
    } yield requiredPathKey 

    val pathKeys = targetPath.getRequiredPathKeys ++ requiredPathKeys 

但是请注意,在的getRequiredPathKeys重复。功能程序员厌恶重复。有时过于所以,在我看来,不过,在这种情况下,它可以很容易地删除:

val pathKeys = for { 
     accessPath <- accessPaths + targetPath 
     requiredPathKey <- accessPath.getRequiredPathKeys 
    } yield requiredPathKey 

上面的代码提出另一种改进。如果你看到this question关于Scala的用于解析,你会看到,上面是相当于

val pathKeys = (accessPaths + targetPath).flatMap(accessPath => 
     accessPath.getRequiredPathKeys.map(requiredPathKey => requiredPathKey)) 

map末是多余的,因为它没有做任何事情。实际上,只要yield只返回一个简单的标识符,表达式中就有一个冗余map。删除它给我们:

val pathKeys = (accessPaths + targetPath).flatMap(accessPath => 
     accessPath.getRequiredPathKeys) 

或者,使用Scala的匿名函数参数语法,

val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 

最后,

return pathKeys 

斯卡拉关键字return用于指定在一个异常工作流程 - 该方法执行被终止而不是结束的一个点。不是说这不是没有用,但是,像例外本身一样,不应该没有原因地使用它。在这里,你应该使用

pathKeys 

但是,在这一点上,你的代码变得只有这两条线:

val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 
    pathKeys 

这使得val分配完全redudant。你可以把它从而减少:

(accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 

因此该方法变得

def getAllRequiredPathKeys: Set[PathKey] = { 
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 
} 

现在,我知道我说“终于”回到那里,但有斯卡拉公约的一个更珍闻申请。每当一个方法包含单个表达式而不是多个语句时,约定就是忽略大括号。换句话说,这样做:

def getAllRequiredPathKeys: Set[PathKey] = 
    (accessPaths + targetPath).flatMap(_.getRequiredPathKeys) 

或者,如果空间允许的话,把所有东西放在一行上。事实上,如果您删除getAllRequiredPathKeys类型,它将很好地适合。另一方面,鼓励公开方法明确的回报类型。

所以这会给你一个斯卡拉不可变的Set。假设您的输入和输出必须是Java的Set。在这种情况下,除非您愿意在Java和Scala集之间进行转换,否则我没有看到任何可以简化代码的操作。你可以是这样做的:

trait PathTemplate { 
    def getRequiredPathKeys:java.util.Set[PathKey] 
} 

import scala.collection.JavaConverters._ 

class MyClass(accessPaths:java.util.Set[PathTemplate], targetPath:PathTemplate){ 
    def getAllRequiredPathKeys: java.util.Set[PathKey] = 
     (accessPaths.asScala + targetPath).flatMap(_.getRequiredPathKeys.asScala).asJava 
} 

然而,这使用Scala的可变Set,这意味着每个操作创建一个新的Set将复制旧Set所有内容。

+0

哇,真是太棒了。我仍在消化所有这些,但它是解决方案演变的一个很好的描述。 Thankyou :) – Paul 2011-05-13 15:41:49

+0

这是一个很棒的漫步,非常适合Java难民!谢谢! – 2011-06-20 11:22:42

相关问题