如何修复asInstanceOf用法的警告

时间:2018-05-18 11:30:59

标签: scala static-code-analysis

我正在使用替罪羊进行Scala静态代码分析,我在一段代码上收到警告。这是完整的警告

Warning  Use of asInstanceOf  com.sksamuel.scapegoat.inspections.unsafe.AsInstanceOf
asInstanceOf used near cursor.next().asInstanceOf[com.mongodb.casbah.Imports.BasicDBObject]. Consider using pattern matching.

警告指向的行是

obj = cursor.next().asInstanceOf[BasicDBObject]

属于这段代码

val q = QueryBuilder.start(fieldName.toString()).is(value)
val cursor = collectionMongo(ARTGROUP_COLLECTION_NAME).find(q.get)
var obj = new BasicDBObject
try {
  while (cursor.hasNext) {
    obj = cursor.next().asInstanceOf[BasicDBObject]
    log.debug(" obj.tostring" + obj.toString())
    retunedList += parseArtGroup(obj)
   }
} catch {
}

如何在上面的代码中使用模式匹配?

1 个答案:

答案 0 :(得分:3)

Scala强调类型安全,比大多数普遍的语言更强调,这就是为什么铸造通常被视为代码气味的原因。出于同样的原因,语言设计者决定使用类似命名的isInstanceOf[T]asInstanceOf[T]进行强制转换,以便在运行时查询类型并进行转换。

为了解决这个问题,同时仍然能够与不那么类型安全的库进行交互,通常会建议使用模式匹配。

以下是您的代码片段,其中包含模式匹配而不是强制转换:

val q = QueryBuilder.start(fieldName.toString()).is(value)
val cursor = collectionMongo(ARTGROUP_COLLECTION_NAME).find(q.get)
var obj = new BasicDBObject
try {
  while (cursor.hasNext) {
    cursor.next() match {                // HERE
      case basicDbObj: BasicDBObject =>  // HERE
        obj = basicDbObj                 // HERE
    }    
    log.debug(" obj.tostring" + obj.toString())
    retunedList += parseArtGroup(obj)
  }
} catch {
}

模式匹配是一种Scala功能,允许您在其他语言中应用类似于switch/case构造的内容,但具有更具表现力的语义。

模式匹配还允许您以有意义的方式解构输入,例如:

List(1, 2, 3, 4) match {
  case head :: tail =>
    println(s"The first element is $head and then comes $tail")
}

值得一提的是,如果您没有涵盖所有可能的情况,您可能会收到不同的警告,因为如果不满足匹配条款,您可能会抛出MatchError

如果您无法完全覆盖所有可能的情况,您可能需要考虑符号通配符捕获所有模式的_令牌,如下例所示:

cursor.next() match {
  case basicDbObj: BasicDBObject =>
    obj = basicDbObj
  case _ => // default case
    ??? // probably some error handling
}

您可以在Scala in the official documentation中阅读有关模式匹配的更多信息。这是一篇写得很好的文档,您将对Scala这个非常强大的功能有很多了解。

我现在要添加的一件好事是,Scala的try/catch构造使用了类似的语法。

try {
  throw new RuntimeException("kaboom :)")
} catch {
  case e: RuntimeException =>
    println(e.getMessage) // prints "kaboom :)"
}

如果您不确定要捕获的内容,Scala会附带一个非常有用的功能来解构非致命异常:

import scala.util.control.NonFatal

try {
  throw new RuntimeException("kaboom again!")
} catch {
  case NonFatal(e) =>
    println(e.getMessage) // prints "kaboom again!"
}

引用the official documentation

  

非致命Throwables的提取器(注意:有关提取器的更多内容here )。不符合VirtualMachineError等致命错误(例如,OutOfMemoryErrorStackOverflowErrorVirtualMachineError的子类),ThreadDeathLinkageError,{{ 1}},InterruptedException

您可能希望在代码中使用与此类似的内容。

另一方面,在您的代码中,您似乎正在解析迭代器中的对象并将它们添加到列表中。它超越了你的问题,但我想提出一个小建议。

您可能希望使用以下内容来执行此操作:

ControlThrowable

实际情况可能是您实际上并不需要将结果附加到import scala.util.Try Try(cursor.collect { case o: BasicDBObject => parseArtGroup(o) }).foreach(returnedList ++= _) ,但我会让您成为法官,因为我不知道你的代码。如果您认为这种方法有意义,可以在returnedList here上详细了解并了解Try方法here