Java匿名内部类和lambda表达式初探


前言

最近在写java事件处理的时候,一开始我基本都是使用传统的java事件处理机制,把实现的接口对象new出来,传到监听器里面去,然后后面用匿名内部类以及lambda表达式的写法都写了一遍(在很多框架的源码里面匿名内部类以及lambda表达式感觉比较常见),然后我发现我对这个匿名内部类以及lambda表达式只是知道写法,却并不知所以然,我也很好奇三种写法中编译器大概做了哪些优化,所以略微去了解了一下做做笔记。


一、匿名内部类

需要创建不会被再次使用的对象,在这种情况下,适合使用匿名内部类。这种类没有名称,是在同一条语句中声明和创建的。既然是匿名类,所以你无法在别的地方实例化和使用这个类。匿名内部类也可用于接口(interface)的实现。前提是必须是类或者接口,且类或者接口中只有一个抽象方法的时候,从匿名内部类到lambda相当于是帮我们越来越简化代码,这样我们简化代码的时候,编译器才能匹配到你的具体实现)

1.特点

匿名对象:没有名字的对象。 new ClassName().run();  
非匿名对象:含有名字的对象。 ClassName c=new ClassName(); c.run();

2、语法(举例说明)

举例1:创建一个父类,使用匿名内部类就相当于创建一个父接口的实现子接口。

public abstract class Animal {
    public abstract void eat();
}

/**
 * 前提
 * 必须是类或者接口
 * 类或者接口中只有一个抽象方法的时候
 */
public class Demo01 {
    public static void main(String[] args) {
        //这个匿名内部类整体就等效于:是Animal父类的子类对象
        new Animal(){
            @Override
            public void eat() {
                System.out.println("修狗");
            }
        };
        //调用方法1
        new Animal(){
            @Override
            public void eat() {
                System.out.println("修狗");
            }
        }.eat();
        //调用方法二
        String name="中华田园犬";
//通过匿名内部类访问局部变量,在JDK8版本之前,需要用final关键字,现在可以自动默认了
        Animal a=new Animal() {
            @Override
            public void eat() {
                System.out.println(name+"修狗");
            }
        };
        a.eat();
    }
}

举例2:创建两个父接口(方法中一个带参数,一个不带参数),并使用匿名内部类、lambda进行函数传参

public interface Inter {
    public void method();
}
public interface Inter2 {
     int add(int x,int y);
}
public class Demo02 {
    public static void main(String[] args) {
        //如果想调用function方法,常规方法要先创建一个实现Inter的接口(new出来)传进去
        //但是使用匿名内部类可以直接这样
        function(new Inter() {
            @Override
            public void method() {
                System.out.println("匿名内部类重写后的方法");
            }
        });
        //使用Lambda表达式,更加简介,直接写逻辑实现,具体的匹配编译器会帮我们实现
        function(()->{
            System.out.println("Lambda表达式改写后的方法");
        });
        //带参数的匿名内部类
        function2(new Inter2() {
            @Override
            public int add(int x, int y) {
                return x+y;
            }
        });
        //带参数的Lambda表达式
        function2((int x,int y)->{
            return x+y;
        });
    }
    public static void function(Inter i){
        i.method();
    }
    public static void function2(Inter2 i){
        int num=i.add(1,2);
        System.out.println("带参数的Lambda表达式:"+num);
    }
}

二、lambda表达式

lambda表达式是一个匿名函数,它是推动Java 8发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda表达式可以使代码变的更加简洁紧凑。

1.特点

(形式参数)->{代码块}

Lambda表达式组成三要素:括号,箭头,代码块

Lambda表达式的代码分析
● (): 里面没有内容,可以看成是方法形式参数为空
● ->:用箭头指向后面要做的事情
● {}: 包含一段代码,我们称之为代码块,可以看成是方法体中的内容

2.语法(举例说明)

用匿名内部类和Lambda表达式分别启动一个线程,相对于匿名内部类,我们会发现 Lambda 表达式更简洁。

public class RunableDemo01 {
    public static void main(String[] args) {
        //匿名内部类的方式启动一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动啦");
            }
        }).start();
        //Lambda表达式的方式启动一个线程
        new Thread(()-> System.out.println(Thread.currentThread().getName()+"线程启动啦")).start();
    }
}

三、java事件处理模式

处理模式流程如图所示(wps画的略微有些粗糙,总体思想意思差不多)
在这里插入图片描述
处理事件四种常见写法(第一种写法贴全部demo代码,剩余三种是在第一种写法的基础上贴变化的部分)

1.写法1

创建了实现了ActionListener接口的监视器listener,并 text.addActionListener(listener)传进去。

public class Demo03{
    public static void main(String[] args) {
        WindowActionEvent windowActionEvent=new WindowActionEvent();
        windowActionEvent.setBounds(100,100,310,260);
        windowActionEvent.setTitle("处理ActionEvent事件");
    }
}
class WindowActionEvent extends JFrame {
        JTextField  text ;
        ReaderListen listener;
        public WindowActionEvent(){
            init();
            setVisible(true);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
        void init(){
            setLayout(new FlowLayout());
            text=new JTextField(10);
            //传统思路
            listener=new ReaderListen();
            text.addActionListener(listener);
            
            add(text);
        }
}
class ReaderListen implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        String str=e.getActionCommand();
        System.out.println(str.length());
    }
}

2.写法2

不需要创建上面的类ReaderListen ,直接使用匿名内部类传参,

//使用匿名内部类,简化代码
text.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("使用匿名内部类");
    }
});

3.写法3

甚至不需要知道类名,直接写实现逻辑,不过注意使用前提是类或者接口中只有一个抽象方法的时候


```bash
//使用Lambda表达式,更加简介
text.addActionListener(d->{
    System.out.println("使用Lambda表达式");
});

4.写法4

在实际开发中,如果事件处理的逻辑比较复杂,考虑到维护代码质量以及低耦合的考虑,会将第三种表达式中的逻辑实现封装成一个函数里面。

void init(){
    setLayout(new FlowLayout());
    text=new JTextField(10);
    //传统思路
    //使用Lambda表达式,d是参数
    text.addActionListener(d->{
        onClick(d);
    });

    add(text);
}
//用自定义函数onClick封装逻辑
public void onClick(ActionEvent event){
    System.out.println("lambda但是解耦版");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值