Lambda运算符()->如何工作?

时间:2019-01-25 04:39:45

标签: java spring akka

我想了解以下代码的工作原理。

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

@Named
@Scope("prototype")
public class StateOne extends AbstractStateActorActor<StatObject> {

    @Inject
    public StateOne(final Props prop, final StatRegistry statRegistry) {
        super("test", transformationConfig, GenericStateObject.class, statRegistry);
    }
}

@FunctionalInterface
public interface StateHandlerDef {
    Class<? extends AbstractUntypedActor> getHandlerClass();
}

这是工作代码。

我想了解一下,这里的bean创建是如何工作的。

下面的代码创建一个bean。

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

StateOne类具有一个构造函数。但是,这将在不传递构造函数参数的情况下创建Bean。同样,返回类型是一个函数接口,它不是由实际状态类实现的,并且不确定如何工作。这是基于Akka演员模型的。

AbstractStateActorActor extends AbstractUntypedActor

在这里,我想以编程方式设置Bean名称,而不是通过注释来设置。

  

@Bean(“测试”)

如果我尝试通过BeanPostProcessor以编程方式设置Bean名称,则会引发错误,即无法使用new创建实例,而应使用actorof创建实例。

Caused by: akka.actor.ActorInitializationException: You cannot create an instance of [com.test.Test] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
    at akka.actor.ActorInitializationException$.apply(Actor.scala:181) ~[akka-actor_2.11-2.4.19.jar:na]

对此有任何帮助吗?

3 个答案:

答案 0 :(得分:2)

要理解这种想法。您尝试扩展的库(在本例中为akka)需要知道将要处理状态的类。为此,它获取类型为StateHandlerDef的实例(bean)。此实例是通过以下代码中的lambda表达式创建的:

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class;
}

等效于:

@Bean
public StateHandlerDef handler() {
    return new StateHanderDefImpl();
}

该库将使用它来获取StateOne.class,为此它将寻找一个bean,并从依赖注入框架中获取它。该bean在这里定义:

@Named
@Scope("prototype")
public class StateOne extends AbstractStateActorActor<StatObject> {

    @Inject
    public StateOne(final Props prop, final StatRegistry statRegistry) {
        super("test", transformationConfig, GenericStateObject.class, statRegistry);
    }
}

DI框架将通过将其所需的依赖项注入其构造函数中,从而从此类创建Bean。

答案 1 :(得分:1)

StateHandlerDef的功能接口以某种方式表示使用Lambda定义在其类定义中定义的吸气剂功能getHandlerClass()。带有以下声明;

@Bean
public StateHandlerDef handler() {
    return () -> StateOne.class; // a supplier, no input, returns value (getter)
}

我们本质上是通过定义StateHandlerDef方法来实现getHandlerClass()接口。因此,lambda的返回值与getter方法相同,StateOne的类型为Class<? extends AbstractUntypedActor>

所以在某种程度上,我们创建的bean类似于以下内容;

public interface StateHandlerDef {
    Class<? extends AbstractUntypedActor> getHandlerClass();
}

public class StateHandlerDefImpl implements StateHandlerDef {

    // explicit way of writing lambda "() -> StateOne.class"
    Class<? extends AbstractUntypedActor> getHandlerClass() {
        return StateOne.class;
    }
}

@Bean
public StateHandlerDef handler() {
    return new StateHandlerDefImpl();  // then we use the getter thru this bean.
}

使用@FunctionalInterface,我们可以跳过上述接口的实现,而只需将接口本身与传递的lambda(即Supplier)一起使用。

现在您可以执行此操作;

@Autowire
private StateHandlerDef handler;

public .. someLogic() {
    ...
    handler.getHandlerClass();  // will trigger the lambda, returning `StateOne.class`
    ...
}

您可以通过仅更改其创建方法的名称来更改Bean的名称。 @Bean handler()将生成名称为handler的bean。

我试图简化,希望它可以理解,否则请检查this

答案 2 :(得分:1)

@FunctionInterface是一种特殊的接口,实际上限制了用户不要包含多个SAM(单一抽象方法)。对于下面的示例,我们有一个方法,它将提供任何扩展Object类的类。

@FunctionalInterface
interface ClassHandleDef {
  Class<? extends Object> getHandlerClass();
}

现在,我们正在创建接口ClassHandleDef的匿名类,并提供gethandlerClass方法的主体。

new ClassHandleDef() {
        @Override
        public Class<? extends Object> getHandlerClass() {
            return String.class;
        }
    };

现在,我们正在删除不需要的多余代码。根据lambda表达式,删除所有多余的代码,并提供参数(如果存在)以及该方法的主体定义以及lambda运算符。

() -> String.class;
  • 如果存在单行方法定义,则无需显式编写return语句。
  • 如果有单个参数,则不需要括号。例如

    a-> a * 2;

希望,您了解lambda表达式的工作流程。感谢您抽出宝贵的时间阅读这篇文章。