0

It happen with id. (Non-value field is accessed in 'hashCode()')

How can I fix it?

Here is my code:

import java.util.Date

case class Category() {
    var id: Integer = _
    var parentId: Integer = _
    var name: String = _
    var status: Boolean = _
    var sortOrder: Integer = _
    var createTime: Date = _
    var updateTime: Date = _

    def this(id: Integer, parentId: Integer, name: String, status: Boolean, sortOrder: Integer, createTime: Date, updateTime: Date) {
        this()
        this.id = id
        this.parentId = parentId
        this.name = name
        this.status = status
        this.sortOrder = sortOrder
        this.createTime = createTime
        this.updateTime = updateTime
    }

    override def hashCode(): Int = {
        if (id != null) id.hashCode() else 0
    }
}

If I change var id to val id, it will be ok. But I need setter, I cant't set it as a val.

AurevoirXavier
  • 2,543
  • 2
  • 17
  • 25
  • Your `hashCode()` method works for me (Scala 2.12.2). It is very, **very**, bad Scala, but it compiles and runs. (I did have to change the name of the `this()` method.) – jwvh May 21 '17 at 06:09
  • @jwvh Lol, I'm a beginner of scala~ Can you check my answer, it is right? – AurevoirXavier May 21 '17 at 07:41

2 Answers2

1

Non value field in hashCode means you're relaying on a mutable field to generate the classes hashcode, which may be dangerous, depending how you use that class. For example, assume you have a HashMap[Category, String], you place an entry in the hash map and them mutate the id field, now that hashmap can no longer find the class instance by it's hashcode.

You're treating a case class like it's a regular, mutable Java class. Case classes provides the mechanism of encapsulating immutable data in a syntax convenient way (where you also get a few nice things for free, such as hashCode, equals, etc). What you can do is make your case class accept parameters via it's primary constructor:

case class Category(id: Int,
                    parentId: Int,
                    name: String,
                    status: Boolean,
                    sortOrder: Int,
                    createTime: Date,
                    updateTime: Date) {
  override def hashCode(): Int = id.hashCode()
}

If you want to update Category, you can use the utility copy method defined on a case class:

val cat = Category(id = 1,
                   parentId = 1,
                   name = "Hello",
                   status = true,
                   sortOrder = 1,
                   createTime = new Date(123132123L),
                   updateTime = new Date(52234234L))

val newCat: Category = cat.copy(id = 2)

Another way of approaching this (which I like less TBH) would be to make all your fields an Option[T] with a default value set to None:

case class Category(id: Option[Int] = None,
                    parentId: Option[Int] = None,
                    name: Option[String] = None,
                    status: Option[Boolean] = None,
                    sortOrder: Option[Int] = None,
                    createTime: Option[Date] = None,
                    updateTime: Option[Date] = None) {
  override def hashCode(): Int = id.map(_.hashCode()).getOrElse(0)
}

And then updating them once you can populate the class with data:

val cat = Category()
val newCat = cat.copy(id = Some(1))
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
0

After I try many times, I think this should be a good choice. Any ideas?

override def hashCode(): Int = {
    if (getId != null) getId.hashCode() else 0
}
AurevoirXavier
  • 2,543
  • 2
  • 17
  • 25