【问题标题】:Catch exception in Scala constructor在 Scala 构造函数中捕获异常
【发布时间】:2013-09-07 01:24:19
【问题描述】:

这个 Java 代码的 Scala 等价物是什么,someMethodThatMightThrowException 在别处定义?

class MyClass {
    String a;
    String b;

    MyClass() {
        try {
            this.a = someMethodThatMightThrowException();
            this.b = someMethodThatMightThrowException();
        } finally {
            System.out.println("Done");
        }
    }
}

【问题讨论】:

    标签: scala exception-handling constructor


    【解决方案1】:
    class MyClass {
      private val (a, b) =
        try {
          (someMethodThatMightThrowException(),
           someMethodThatMightThrowException())
        } finally {
          println("Done")
        }
    }
    

    try 是 Scala 中的表达式,因此您可以使用它的值。使用元组和模式匹配,您可以使用语句来获取多个值。

    您也可以使用与 Java 中几乎相同的代码:

    class MyClass {
      private var a: String = _
      private var b: String = _
    
      try {
        a = someMethodThatMightThrowException()
        b = someMethodThatMightThrowException()
      } finally {
        println("Done")
      }
    }
    

    【讨论】:

    • 时髦。不过,有点希望您删除 java 替代品。除非您愿意在初始化程序中添加分号和 null 以使其看起来更加真实。编辑:private 是从哪里来的?
    • @som-snytt:删除 java 替代方案后,我应该将解决方案替换为 sealed case classprivate 构造函数,并将不安全的调用移至工厂 apply 方法。 private来自我的懒惰,应该是private[PackageName]
    【解决方案2】:

    伴随对象

    case class MyClass(a: String, b: String)
    
    object MyClass {
       def apply() = try { 
          new MyClass(
             a = someMethodThatMightThrowException(), 
             b = someMethodThatMightThrowException()
          ) 
       } finally {
          println("Done") 
       }
    }
    

    构造函数重载有点困难,因为我们不能包装 this(...):

    def tryIt[T](something: => T) = try{
          something
       } finally {
          println("Done") 
       }
    
    case class MyClass(a: String, b: String) {
       def this() = this(
          tryIt(someMethodThatMightThrowException),  
          tryIt(someMethodThatMightThrowException)
       ) 
    }
    

    【讨论】:

    • 构造函数重载:<console>:2: error: 'this' expected but 'try' found.
    • 你是对的。我现在正在尝试使用构造函数找到另一个解决方案
    【解决方案3】:

    如果发生异常,分配的ab 是什么?将ab 包裹在Try 中以处理异常情况。您还可以对这些进行模式匹配以提取值。

    scala> class MyClass(val a: Try[String], val b: Try[String])
    defined class MyClass
    
    scala> new MyClass(Try("foo"(0).toString), Try("foo"(3).toString))
    res0: MyClass = MyClass@6bcc9c57
    
    scala> res0.a
    res1: scala.util.Try[String] = Success(f)
    
    scala> res0.b
    res2: scala.util.Try[String] = Failure(java.lang.StringIndexOutOfBoundsException: String index out of range: 3)
    
    scala> res0.a.get
    res3: String = f
    
    scala> res0.b.get
    java.lang.StringIndexOutOfBoundsException: String index out of range: 3
            at java.lang.String.charAt(String.java:658)
            ...
    

    编辑评论。对ab 使用默认参数

    null 不好,但这就是你要求的。见Option

    class MyClass(val a: Try[String] = null, val b: Try[String] = null)
    
    scala> new MyClass(Success("a"))
    res50: MyClass = MyClass@625aaaca
    
    scala> res50.a
    res51: scala.util.Try[String] = Success(a)
    
    scala> res50.b
    res52: scala.util.Try[String] = null
    
    scala> new MyClass(b = Success("b"))
    res53: MyClass = MyClass@68157e85
    
    scala> res53.a
    res54: scala.util.Try[String] = null
    
    scala> res53.b
    res55: scala.util.Try[String] = Success(b)
    

    【讨论】:

    • 如果构造函数中没有设置Object成员,则默认为null
    • 您可以在构造函数中使用默认参数。这样就变成了class MyClass(val a: Try[String] = null, val b: Try[String] = null)。不过,我不鼓励使用null。查看Option 类型,甚至只是一个空的String
    【解决方案4】:

    更接近的东西怎么样:

    scala> def foo = ???
    foo: Nothing
    
    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    case class Foo(a: String = Foo.afoo, b: String = Foo.bfoo)
    object Foo {
    import util._
    def afoo = Try (foo) recover { case _ => "a" } get
    def bfoo = Try (foo) recover { case _ => "b" } get
    }
    
    // Exiting paste mode, now interpreting.
    
    warning: there were 2 feature warning(s); re-run with -feature for details
    defined class Foo
    defined object Foo
    
    scala> Foo()
    res0: Foo = Foo(a,b)
    

    【讨论】:

    • 帮我把这些点连接起来......当构造函数完成时,我将“完成”打印到标准输出的示例(即使它引发了异常)。
    • ctor 仍然可以为所欲为,包括打印 Done。正如其他 cmets 所建议的那样,困难的部分是决定哪个移动部分应该处理故障(或提供默认值,如此处)。在同伴的工厂里做这一切可能更惯用。您也可以添加一个方法,该方法调用 apply 然后报告完成。做什么?初始化方法真的是未来吗?也许你想要一个返回 Try[Foo] 的工厂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    相关资源
    最近更新 更多