java的λ变革

序言

java方法参数都是基本类型、对象(数组和引用)。当我们使用这些参数时,他们所带的属性,方法(行为)必须是固定已知,否则程序不可能运行出正确的结果。所以当我们方法传递一个引用类型参数前必须实列化它,如果属性依赖于它的方法,还要运行它相关方法,确保属性的正确,才可以使用。如果对象参数行为依赖调用者的内部变量,则这就出现了回调,那么就得使用匿名内部类。监控行为很常见。

public class ZooKeeperConnection {
 
   // declare zookeeper instance to access ZooKeeper ensemble
   private ZooKeeper zoo;
   final CountDownLatch connectedSignal = new CountDownLatch(1);
 
   // Method to connect zookeeper ensemble.
   public ZooKeeper connect(String host) throws IOException,InterruptedException {
	
      zoo = new ZooKeeper(host,5000,new Watcher() {
		
         public void process(WatchedEvent we) {
 
            if (we.getState() == KeeperState.SyncConnected) {
            //初始值为1,所以一旦成功建立连接,就会放行connet
               connectedSignal.countDown();
            }
         }
      });
	//阻塞主线程,直到成功建立连接,返回ZooKeeper对象
      connectedSignal.await();
      return zoo;
   }
 
   // Method to disconnect from zookeeper server
   public void close() throws InterruptedException {
      zoo.close();
   }
}

那么能不能不要匿名内部类的复杂,而可以在使用相关属性前,正确的运行了它的方法呢。这也是大多数顺序流运行的代码逻辑。

public class XyzWatcher implements Watcher {
    @Override
    public void process(WatchedEvent watchedEvent) {
        final CountDownLatch connectedSignal = new CountDownLatch(1);
        if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
            connectedSignal.countDown();
        }
        try {
            connectedSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ZooKeeperConnection {
 
    // declare zookeeper instance to access ZooKeeper ensemble
    private ZooKeeper zoo;
    //public final CountDownLatch connectedSignal = new CountDownLatch(1);
 
    // Method to connect zookeeper ensemble.
    XyzWatcher xyz = new XyzWatcher();
 
    public ZooKeeper connect(String host) throws IOException,InterruptedException {
        zoo = new ZooKeeper(host,5000,xyz);
        return zoo;
    }
 
    // Method to disconnect from zookeeper server
    public void close() throws InterruptedException {
        zoo.close();
    }
}

上面代码又复杂了,其实我们的目的就是创建一个ZooKeeper对象,创建过程中有条件(一旦成功建立连接才返回对象),这一行为整体作为参数传递才是我们的目的,但面向对象编程是抽象级别不够,它只能把数据抽象为对象,但对行为无能为力。函数式编程是对行为进行抽象,λ表达式产生了。

public class ZooKeeperConnection {
 
   // declare zookeeper instance to access ZooKeeper ensemble
   private ZooKeeper zoo;
   final CountDownLatch connectedSignal = new CountDownLatch(1);
 
   // Method to connect zookeeper ensemble.
   public ZooKeeper connect(String host) throws IOException,InterruptedException {
	
      zoo = new ZooKeeper(host,5000,(Watcher watcher,WatchedEvent we) ->watcher.process(we) );
      return zoo;
   }
 
   // Method to disconnect from zookeeper server
   public void close() throws InterruptedException {
      zoo.close();
   }
}

函数式接口

函数式接口是未声明sealed只有一个abstract方法(除了Object之外的方法),因此表示单个函数契约。它可以用@FunctionalInterface标识,用来提醒编译器检查接口定义是否满足函数接口定义,当违反这一约定时,编译器会报错。正确的函数式接口也可以不标。

//是
interface Runnable {
    void run();
}
//不是,它只有一个Object的equals方法,未声明任何其他抽象方法
interface NonFunc {
    boolean equals(Object obj);
}
//是,虽然它是上一个的子接口,但有一个非Object抽象方法
interface Func extends NonFunc {
    int compare(String o1, String o2);
}
//是它只有一个非Object抽象方法
interface Comparator<T> {
    boolean equals(Object obj);
    int compare(T o1, T o2);
}
//不是,它声明了两个非Object的抽象方法
interface Foo {
    int m();
    Object clone();
}

只有一个抽象方法的接口才是函数接口,函数接口目的就是将函数运行过程作为参数传递,如果接口中有多个方法,调用时就无法得知哪一个方法,编译器也无法通过。

函数接口运用——构造方法

这就是一个事件工厂,可以生产出任何类的实例。java8之前,我称之为抽象工厂。

public interface EventFactory<T>
{
    /**
     * Implementations should instantiate an event object, with all memory already allocated where possible.
     *
     * @return T newly constructed event instance.
     */
    T newInstance();
}

每一个具体工厂继承它,然后实现newInstance()方法,生产对象。

public class LongEventFactory implements EventFactory {
	@Override
	public Object newInstance() {
		return new LongEvent();
	}
}

其实就是new LongEvent()的调用,那有了方法引用之后,就一句。不用具体的工厂实现。但只接口中方法只有无参的,所以调用的是无参构造器,要想调用有参构造器,函数接口中的方法加上参数。但是这是Disruptor框架的,改不了,所以我们在创建无参事件时,可以直接通过函数接口。有参时,还是需要工厂实现类,而且可以添加创建事件对象逻辑。

EventFactory<LongEvent> eventFactory = LongEvent::new;

λ原理

main方法需要一个匿名内部类,来输出Integer.valueOf(1)的结果。现在用Factory接口来实现。Factory<Integer> f就相当于匿名内部类的对象。make调用时正真触发λ表达式相当于调用匿名内部类中的方法。

//函数式接口
public interface Factory<T> {
    T make(String s);
}
public class LamdaTest {

    public static void main(String[] args) {
    //lamda表达式
        Factory<Integer> f = (Factory<Integer>) a -> Integer.valueOf(1);
        System.out.println(f.make(null));
    }
}

调用方法

λ表达式外部方法字节码。这时的字节码make参数为null,静态合成方法时,我们把参数改为100,不要产生歧义了
在这里插入图片描述
在这里插入图片描述
R大的lamda
从字节码看Lambda表达式本质
Java底层原理专题系列之带你看透Lambda表达式的本质
方法调用指令之invokevirtual
Java Lambda 表达式实现原理<长文 - 慎重>
MethodHandle标记final影响内联问题
一线开发大牛带你深度解析探讨模板解释器,解释器的生成
java Methodhandle效率
方法引用和invokedynamic重点
杨易博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值