Akka Streams GraphStage

时间:2018-02-10 12:09:26

标签: java scala akka-stream

在Akka Streams中建议使用GraphStage,但我找不到任何关于在Java中使用getStageActor()方法的文档(我发现使用Scala的所有文档)。

如何将以下代码转换为Java?

lazy val self: StageActor = getStageActor(onMessage)

private def onMessage(x: (ActorRef, Any)): Unit =
{
  x match {
    case (_, msg: String) =>
      log.info("received msg, queueing: {} ", msg)
      messages = messages.enqueue(msg)
      pump()
  }
}

2 个答案:

答案 0 :(得分:0)

之前我没有使用getStageActor(),因此无法提供太多帮助。至于从Scala到Java的代码转换,如果需要允许,请打包一个包含Scala版本类的jar供Java app使用;否则,请考虑使用Java反编译器(例如cfr,procyon)来反编译Scala编译的类,并根据需要优化反编译的Java代码。

例如,反编译以下虚拟Scala代码将有助于揭示lazy valpattern matching的骨架Java方式:

class Foo {
  lazy val self = dummy(bar(_: String))
  def dummy(u: Unit) = 1
  private def bar(x: String): Unit = {
    x match {
      case "blah" => println(s"x = $x")
    }
  }
}

如下面的反编译代码所示,lazy val在Java中完成,其值包含在synchronized块内,并带有bitmap$0布尔标志,pattern matching转换为ifMatchError$ java -jar /path/to/decompiler/cfr_0_125.jar Foo.class private int self; private volatile boolean bitmap$0; private int self$lzycompute() { Foo foo = this; synchronized (foo) { if (!this.bitmap$0) { new Serializable(this){ public static final long serialVersionUID = 0L; private final /* synthetic */ Foo $outer; public final void apply(String x$1) { this.$outer.Foo$$bar(x$1); } { if ($outer == null) { throw null; } this.$outer = $outer; } }; this.self = this.dummy(BoxedUnit.UNIT); this.bitmap$0 = true; } return this.self; } } public int self() { return this.bitmap$0 ? this.self : this.self$lzycompute(); } public int dummy(BoxedUnit u) { return 1; } public void Foo$$bar(String x) { String string = x; if ("blah".equals(string)) { Predef$.MODULE$.println((Object)new StringContext( (Seq)Predef$.MODULE$.wrapRefArray((Object[])new String[]{"x = ", ""}) ).s((Seq)Predef$.MODULE$.genericWrapArray((Object)new Object[]{x})) ); BoxedUnit boxedUnit = BoxedUnit.UNIT; return; } throw new MatchError((Object)string); } 例外:

getNewsItems().then((result)=>{
    if (result === "what you need") {
        // do here what you want with the result data
    } else {
         buildNewsItemsViaHttp().then((result)=>{
             if (result === "what you need") {
                  // do here what you want with the result data
             } else {
                 buildNewsItemsViaLocalJSON.then((result)=>{
                 // do here what you need with result
             })
         }
    })
}})

答案 1 :(得分:0)

根据getStageActor method documentation,它接受​​类型

的值
scala.Function1<scala.Tuple2<ActorRef,java.lang.Object>, scala.runtime.BoxedUnit>

在Scala中看起来像

((ActorRef, AnyRef)) => Unit

在Java中,此类型在语义上等效(使用Function接口)

Function<Tuple<ActorRef, Object>, Void>

其中Tuple<A, B>是一个包含两个AB类型值的类。

因此,要调用getStageActor方法,您需要创建上述类型的值。您可以通过构建扩展AbstractFunction1的类的实例来直接执行此操作:

import scala.Function1;
import scala.Tuple2;
import scala.runtime.AbstractFunction1;
import scala.runtime.BoxedUnit;

getStateActor(new AbstractFunction1<Tuple2<ActorRef, Object>, BoxedUnit>() {
    @Override
    public BoxedUnit apply(Tuple2<ActorRef, Object> args) {
        return BoxedUnit.UNIT;
    }
});

如果你使用Java 8,那么使用lambda表达式有一些语法上更好的方法。

如果您使用Scala 2.12+,那么scala.Function1是一个功能接口,您可以直接使用lambda表达式:

getStateActor((args: Tuple2<ActorRef, Object>) -> BoxedUnit.UNIT);

如果您使用旧版本的Scala,那么由于编译了特征的方式,Function1不是功能接口,您需要使用scala-java8-compat库。有了它,代码看起来像

import static scala.compat.java8.JFunction.*;

getStateActor(func((args: Tuple2<ActorRef, Object>) -> BoxedUnit.UNIT));

然后,要实现该函数的逻辑,您可以使用_1()_2()方法访问元组的元素:

(args: Tuple2<ActorRef, Object>) -> {
    Object msg = args._2();
    if (msg instanceof String) {
        log.info("received msg, queueing: {} ", msg);
        messages = messages.enqueue((String) msg);
        pump();
    }
    return BoxedUnit.UNIT;
}

这是您想要转换的逻辑的直接翻译。