Scala报错:value get is not a member of java.io.Serializable问题排查
Scala: 为什么添加键检查逻辑后出现
value get is not a member of java.io.Serializable错误? 我写了两段功能类似的Scala代码,都是实现用户数据存入Map并通过键获取的功能。Code1运行正常,但Code2添加了键存在性检查后,出现了value get is not a member of java.io.Serializable的错误。下面是两段代码和报错信息:
Code1(正常运行)
class user(var name:String,var id:Int, var gender:Option[String]) { override def toString="("+ name+","+id+","+gender+")" } object a { def main(args:Array[String]):Unit={ var a=new user("kl",90,Some("Male")) println(a.name,a.id,a.gender)//ACESS VALUES //DEFINING MAP var mm=Map(1-> new user("jh",189,Some("Male")),2->new user("gh",12,None),3 ->new user("io",100,Some("Female"))) // defining method giving o/p value of specific key of mm def getkey(i:Int)= { mm.get(i) } var u1=getkey(readLine("ENTER THE KEY").toInt) // some[user] println(u1.getClass.getName) if(u1.isDefined) { println(u1.get+","+u1.get.name+","+u1.get.id+","+u1.get.gender) } } }
Code2(报错)
class user(var name:String,var id:Int, var gender:Option[String]) { override def toString="("+ name+","+id+","+gender+")" } object a { def main(args:Array[String]):Unit={ var a=new user("kl",90,Some("Male")) println(a.name,a.id,a.gender)//ACESS VALUES //DEFINING MAP var mm=Map(1-> new user("jh",189,Some("Male")),2->new user("gh",12,None),3-> new user("io",100,Some("Female"))) // defining method giving o/p value of specific key of mm def getkey(i:Int)= { //EXTRA LOGIC var a=(mm.keys).toList if(a.contains(i)){mm.get(i)} else {"NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH"} } print("ENTER THE KEY \n") var u1=getkey(1) // some[user] println(u1.get) } }
报错信息
eg1.Option.scala:27: error: value get is not a member of java.io.Serializable println(u1.get) ^ one error found
为什么错误只出现在Code2?
核心原因是Scala的类型推断机制:
- 在Code1中,
getkey方法只返回mm.get(i),而mm是Map[Int, user],所以mm.get(i)的类型是Option[user],因此u1的类型被推断为Option[user],自然可以调用get方法。 - 在Code2中,
getkey方法有两个返回分支:- 键存在时返回
mm.get(i),类型是Option[user] - 键不存在时返回一个
String类型的错误提示
Scala会自动寻找这两个类型的最具体的共同父类型,而Option[user]和String的共同父类型是java.io.Serializable(Scala的多数基础类型和集合都实现了这个接口)。最终u1的类型被推断为Serializable,而这个类型并没有get方法,因此触发报错。
- 键存在时返回
如何修复这个错误?
我们需要让getkey方法的返回类型保持一致,下面提供三种常用的修复方式:
方案1:统一返回Option[user](推荐)
其实mm.get(i)本身就会在键不存在时返回None,完全不需要额外的contains检查(Map的get方法已经内置了这个判断)。如果要提示错误信息,可以在调用方法后处理:
def getkey(i:Int)= { mm.get(i) } // 调用时处理不存在的情况 var u1=getkey(1) u1 match { case Some(user) => println(user) case None => println("NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH") }
如果一定要保留检查逻辑(虽然没必要),可以把else分支改成返回None,保证返回类型统一:
def getkey(i:Int)= { var a=(mm.keys).toList if(a.contains(i)){mm.get(i)} else {None} }
方案2:返回Either[String, user](明确区分成功/失败)
如果需要明确返回错误信息而不是用None占位,可以用Either类型:左边存储错误信息(Left[String]),右边存储成功获取的用户对象(Right[user]):
def getkey(i:Int): Either[String, user] = { mm.get(i) match { case Some(user) => Right(user) case None => Left("NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH") } } // 调用时处理结果 var u1=getkey(1) u1 match { case Right(user) => println(user) case Left(msg) => println(msg) }
方案3:直接抛出异常(不推荐,除非业务必须)
如果希望在键不存在时直接抛出异常,可以调用mm(i)(Map的这个方法会在键不存在时自动抛出NoSuchElementException),或者手动抛出异常:
def getkey(i:Int)= { if(mm.contains(i)){mm(i)} else {throw new NoSuchElementException("NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH")} } // 调用时捕获异常 try { var u1=getkey(1) println(u1) } catch { case e: NoSuchElementException => println(e.getMessage) }
内容的提问来源于stack exchange,提问作者Therii
相关产品推荐
相关产品推荐

