java - 如何在不急于浪费内存的情况下将增量可变 Java 类包装在函数式 Scala 类中?

标签 java scala immutability

[我创建了一个虚构的 JavaClass 只是为了能够测试代码,请参阅问题末尾。]

我使用 Java 库中的增量/可变算法(Weka,但该问题适用于任何 Java 库)。我试图包装它的可变性质。一种方法是像下面的代码一样:

class Model {
  private val model = new JavaModel //just a fake example (could be NaiveBayes)

  //just returns the JavaModel to simplify the question.
  lazy val last_state(items: Seq[Item]) = {
    items foreach model.update
    model
  }
}

问题是有时候,一些中间状态也是需要的。 做到这一点的直接方法是为每个人保留一份副本:

class Model {
  private val model = new JavaModel //just a fake example (could be NaiveBayes)

  def states(items: Seq[Item]): Stream[JavaModel] =
    if (items.isEmpty) Stream.Empty
    else {
      val h = items.head
      val t = items.tail
      val clone = clone(model)      // (AbstractClassifier.makeCopy for weka users)
      clone.update(h)
      clone #:: states(t)
    }
  }
}        

当需要获取最后一个结果时,由于所有不需要的复制,这比第一个代码慢得多。我可以将 lazy val 放入流中。但在对其求值时,实例 model 不再保证相同。

class Lazy (model: JavaModel) {
  lazy val copy = clone(model)     // (AbstractClassifier.makeCopy for weka users)
}

class Model {
  private val model = new JavaModel //just a fake example (could be NaiveBayes)

  def states(items: Seq[Item]): Stream[Lazy] =
    if (items.isEmpty) Stream.Empty
    else {
      val h = items.head
      val t = items.tail
      model.update(h)
      Lazy(model) #:: states(t)
    }
  }
}

这个丑陋的解决方案是我找到的最好的解决方案。我有非私有(private)可变字段等:

class JavaClass(initial:Int = 1) {
  //represents a lot of data structures
  private var state = initial

  //Int represents something more complex
  def update(h: Int) {
    println("Some heavy calculations performed. State=" + state)
    state += 1
  }

  def copy = new JavaClass(state)

  //other methods that make use of the state ...
}

case class Lazy(java_object: JavaClass) {
  var lazy_var: Option[JavaClass] = null

  def copied = if (lazy_var == null) {
    lazy_var = Some(java_object.copy)
    lazy_var
  } else lazy_var
}

class Model {
  def states(items: Seq[Int]): Stream[Lazy] = {
    val java_class = new JavaClass
    def rec(items: Seq[Int], laz: Lazy): Stream[Lazy] =
      if (laz != null && items.isEmpty) Stream.Empty
      else {
        if (laz.lazy_var == null) laz.lazy_var = None
        val h = items.head
        val t = items.tail
        java_class.update(h)
        val new_laz = Lazy(java_class)
        new_laz #:: rec(t, new_laz)
      }
    rec(items, Lazy(null))
  }
}

//Test:
scala>     val m = new Model
m: Model = Model@726b80fa

scala>     val states = m.states(Seq(1, 2, 3, 4, 5))
Some heavy calculations performed. State=1
states: Stream[Lazy] = Stream(Lazy(JavaClass@283e1abf), ?)

scala>     states(0).copied match {case Some(x) => x; case None => -1}
res31: Any = JavaClass@1029bf49

scala>     states(3).copied match {case Some(x) => x; case None => -1}
Some heavy calculations performed. State=2
Some heavy calculations performed. State=3
Some heavy calculations performed. State=4
res32: Any = JavaClass@3cb40c69

scala>     states(3).copied match {case Some(x) => x; case None => -1}
res33: Any = JavaClass@3cb40c69

scala>     states(1).copied match {case Some(x) => x; case None => -1}
res34: Any = -1

最佳答案

一个好的地方是使用“_= posfix”从“人工字段”开始,如本site 的示例中所述。 .也许最好用正确的驼峰命名法打开一个新问题。

  // Fields may be artificial:
  class H {
    private var realX = 0

    def x = realX

    // called for "this.x = <value>":
    def x_=(newX : Int) {
      this.realX = newX
    }
  }

关于java - 如何在不急于浪费内存的情况下将增量可变 Java 类包装在函数式 Scala 类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21972165/

相关文章:

java - 对更改不可变子属性的现有 Javabean 支持

c# - 对于带索引的嵌套选择,ImmutableArray<> 的行为不同于 Array<>

java - 从 Java 字符串中解析文本

java - Spring Boot 响应实体不返回 JSON

java - 计算作为数字因子的两个数组的元素

Java Webstart 选项

json - Play框架Json序列化失败

sql - PostgreSQL jsonb 更新多个嵌套字段

json - 在 Play 中将泛型类型 T 隐式转换为 JsValue!框架

java - 如何编写一个测试友好的不可变值类?