diff --git a/akka-actor-typed/src/main/mima-filters/2.6.19.backwards.excludes/issue-22849.excludes b/akka-actor-typed/src/main/mima-filters/2.6.19.backwards.excludes/issue-22849.excludes
new file mode 100644
index 0000000000..75a6875410
--- /dev/null
+++ b/akka-actor-typed/src/main/mima-filters/2.6.19.backwards.excludes/issue-22849.excludes
@@ -0,0 +1,3 @@
+# #30445 performance improvements for typed javadsl message matchers
+ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.actor.typed.javadsl.BuiltReceive.this")
+ ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.actor.typed.javadsl.BuiltBehavior.this")
\ No newline at end of file
diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala
index 33e676f727..477c22869d 100644
--- a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala
+++ b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/BehaviorBuilder.scala
@@ -34,12 +34,14 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Build a Behavior from the current state of the builder
*/
- def build(): Behavior[T] = new BuiltBehavior(messageHandlers.reverse, signalHandlers.reverse)
+ def build(): Behavior[T] = {
+ new BuiltBehavior[T](messageHandlers.reverse.toArray, signalHandlers.reverse.toArray)
+ }
/**
* Add a new case to the message handling.
*
- * @param type type of message to match
+ * @param type type of message to match
* @param handler action to apply if the type matches
* @tparam M type of message to match
* @return a new behavior builder with the specified handling appended
@@ -50,8 +52,8 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Add a new predicated case to the message handling.
*
- * @param type type of message to match
- * @param test a predicate that will be evaluated on the argument if the type matches
+ * @param type type of message to match
+ * @param test a predicate that will be evaluated on the argument if the type matches
* @param handler action to apply if the type matches and the predicate returns true
* @tparam M type of message to match
* @return a new behavior builder with the specified handling appended
@@ -65,7 +67,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
* Should normally not be used, but when matching on class with generic type
* argument it can be useful, e.g. List.class and (List<String> list) -> {...}
*
- * @param type type of message to match
+ * @param type type of message to match
* @param handler action to apply when the type matches
* @return a new behavior builder with the specified handling appended
*/
@@ -75,7 +77,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Add a new case to the message handling matching equal messages.
*
- * @param msg the message to compare to
+ * @param msg the message to compare to
* @param handler action to apply when the message matches
* @return a new behavior builder with the specified handling appended
*/
@@ -98,7 +100,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Add a new case to the signal handling.
*
- * @param type type of signal to match
+ * @param type type of signal to match
* @param handler action to apply if the type matches
* @tparam M type of signal to match
* @return a new behavior builder with the specified handling appended
@@ -109,8 +111,8 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Add a new predicated case to the signal handling.
*
- * @param type type of signals to match
- * @param test a predicate that will be evaluated on the argument if the type matches
+ * @param type type of signals to match
+ * @param test a predicate that will be evaluated on the argument if the type matches
* @param handler action to apply if the type matches and the predicate returns true
* @tparam M type of signal to match
* @return a new behavior builder with the specified handling appended
@@ -127,7 +129,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/**
* Add a new case to the signal handling matching equal signals.
*
- * @param signal the signal to compare to
+ * @param signal the signal to compare to
* @param handler action to apply when the message matches
* @return a new behavior builder with the specified handling appended
*/
@@ -157,6 +159,7 @@ object BehaviorBuilder {
private val _empty = new BehaviorBuilder[Nothing](Nil, Nil)
// used for both matching signals and messages so we throw away types after they are enforced by the builder API above
+
/** INTERNAL API */
@InternalApi
private[javadsl] final case class Case[BT, MT](
@@ -177,23 +180,25 @@ object BehaviorBuilder {
* INTERNAL API
*/
@InternalApi
-private final class BuiltBehavior[T](messageHandlers: List[Case[T, T]], signalHandlers: List[Case[T, Signal]])
+private final class BuiltBehavior[T](messageHandlers: Array[Case[T, T]], signalHandlers: Array[Case[T, Signal]])
extends ExtensibleBehavior[T] {
- override def receive(ctx: TypedActorContext[T], msg: T): Behavior[T] = receive(msg, messageHandlers)
+ override def receive(ctx: TypedActorContext[T], msg: T): Behavior[T] = receive(msg, messageHandlers, 0)
- override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] =
- receive(msg, signalHandlers)
+ override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] = receive(msg, signalHandlers, 0)
@tailrec
- private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] =
- handlers match {
- case Case(cls, predicate, handler) :: tail =>
- if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg)))
- handler(msg)
- else receive(msg, tail)
- case Nil =>
+ private def receive[M](msg: M, handlers: Array[Case[T, M]], idx: Int): Behavior[T] = {
+ if (handlers.length == 0) {
+ Behaviors.unhandled[T]
+ } else {
+ val Case(cls, predicate, handler) = handlers(idx)
+ if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg)))
+ handler(msg)
+ else if (idx == handlers.length - 1)
Behaviors.unhandled[T]
+ else
+ receive(msg, handlers, idx + 1)
}
-
+ }
}
diff --git a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala
index dea517a390..103b9633b3 100644
--- a/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala
+++ b/akka-actor-typed/src/main/scala/akka/actor/typed/javadsl/ReceiveBuilder.scala
@@ -4,16 +4,13 @@
package akka.actor.typed.javadsl
-import scala.annotation.tailrec
-
-import akka.actor.typed.{ Behavior, Signal }
-import akka.actor.typed.MessageAdaptionFailure
+import akka.actor.typed.{ Behavior, MessageAdaptionFailure, Signal }
import akka.annotation.InternalApi
-import akka.japi.function.{ Function => JFunction }
-import akka.japi.function.{ Predicate => JPredicate }
-import akka.japi.function.Creator
+import akka.japi.function.{ Creator, Function => JFunction, Predicate => JPredicate }
import akka.util.OptionVal
+import scala.annotation.tailrec
+
/**
* Mutable builder used when implementing [[AbstractBehavior]].
*
@@ -33,8 +30,7 @@ final class ReceiveBuilder[T] private (
val builtSignalHandlers =
if (signalHandlers.isEmpty) defaultSignalHandlers[T]
else (adapterExceptionSignalHandler[T] :: signalHandlers).reverse
-
- new BuiltReceive[T](messageHandlers.reverse, builtSignalHandlers)
+ new BuiltReceive[T](messageHandlers.reverse.toArray, builtSignalHandlers.toArray)
}
/**
@@ -196,24 +192,27 @@ object ReceiveBuilder {
*/
@InternalApi
private final class BuiltReceive[T](
- messageHandlers: List[ReceiveBuilder.Case[T, T]],
- signalHandlers: List[ReceiveBuilder.Case[T, Signal]])
+ messageHandlers: Array[ReceiveBuilder.Case[T, T]],
+ signalHandlers: Array[ReceiveBuilder.Case[T, Signal]])
extends Receive[T] {
import ReceiveBuilder.Case
- override def receiveMessage(msg: T): Behavior[T] = receive[T](msg, messageHandlers)
+ override def receiveMessage(msg: T): Behavior[T] = receive[T](msg, messageHandlers, 0)
- override def receiveSignal(msg: Signal): Behavior[T] = receive[Signal](msg, signalHandlers)
+ override def receiveSignal(msg: Signal): Behavior[T] = receive[Signal](msg, signalHandlers, 0)
@tailrec
- private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] =
- handlers match {
- case Case(cls, predicate, handler) :: tail =>
- if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg)))
- handler(msg)
- else receive[M](msg, tail)
- case _ =>
- Behaviors.unhandled
+ private def receive[M](msg: M, handlers: Array[Case[T, M]], idx: Int): Behavior[T] = {
+ if (handlers.length == 0) {
+ Behaviors.unhandled[T]
+ } else {
+ val Case(cls, predicate, handler) = handlers(idx)
+ if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg)))
+ handler(msg)
+ else if (idx == handlers.length - 1)
+ Behaviors.unhandled[T]
+ else
+ receive(msg, handlers, idx + 1)
}
-
+ }
}