多线程01——线程简介,创建方式


多线程01——线程简介、线程创建

Java.Thread

概述

  • 线程简介
  • 线程实现(重点)
  • 线程状态
  • 线程同步(重点)
  • 线程通信问题
  • 高级主题

01 线程简介

任务,进程,线程,多线程

多任务

image-20220328183012205

  • 看起来是多个任务在做,其实本质上我们的大脑在同一时间依旧只做了一件事

多线程

image-20220328183318089

  • 原来是一条路,为了提高使用效率,充分利用道路,加了多个车道

普通方法调用和多线程

image-20220328183550109

程序、进程、线程

  • 在操作系统中运行的程序就是进程,比如你的QQ,播放器,游戏,IDE等等。。。
  • 一个进程可以有多个线程,如视频中同时听声音,看图像,看弹幕,等等

Process(进程)与Thread(线程)

  • 程序:程序是指令和数据的有序结合,其本身没有任何运行的含义,是一个静态的概念
  • 进程:是执行程序的一次执行过程,它是一个动态的概念是系统资源分配的单位
  • 线程:一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位

PS:很多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

本章核心概念

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销。
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

02 线程创建

Thread、Runnable、Callable

三种创建方式

  1. Thread class : 继承Thread类(重点)
  2. Runnbale接口:实现Runnbale接口(重点)
  3. Callable接口:实现Callable接口(了解)

Thread

  • 自定义线程类继承Thread类
  • 重写run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
package com.hao.demo01;

//创建线程方式一:继承Thread类,重写run方法,调用start开启线程
public class TestThread1 extends Thread{
    //线程入口
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---"+i);
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();
        //调用start方法
        testThread1.start();
        //main线程,主线程
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }
}

程序运行结果:

image-20220328192024747

CPU在调度,两个代码交替执行,并行

如果调用run方法的话,就会有先后顺序

总结:线程开启,不一定立即执行,由CPU调度执行

案例:下载图片

程序书写思路:

  1. 新建一个TestThread2的类继承我们的Thread方法实现多线程
  2. 下载图片需要一个下载器,我们再新建一个类,通过调用FileUtils包中的copyURLToFile方法,把一个URL下载为一个文件
  3. 在TestThread2类中构建构造器丢入我们需要下载的图片的地址和文件名
  4. 重写run方法,调用下载器
  5. 在主函数中,创建三个TestThread2类,并且调用三次start()方法进行下载
package com.hao.demo01;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
public class TestThread2 extends Thread{

    private String url;//网络图片地址
    private String name;//保存的文件名
    public TestThread2(String url,String name){
        this.url=url;
        this.name=name;
    }

    //下载图片线程的执行体
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&fmt=auto&app=138&f=JPEG?w=632&h=500","1.jpg");
        TestThread2 t2 = new TestThread2("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
        TestThread2 t3 = new TestThread2("https://img0.baidu.com/it/u=1721391133,702358773&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=625","3.jpg");
        
        t1.start();
        t2.start();
        t3.start();

    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

实现Runnable

  • 实现MyRunnable类实现Runnable接口
  • 实现run()方法,编写线程执行体
  • 创建线程对象,调用start()方法启动线程
package com.hao.demo01;

//创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start
public class TestThread3 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码---"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();
        //创建线程对象,通过线程对象来开启我们的线程,代理
        // 把runnable对象testThread3丢入Thread的对象
        new Thread(testThread3).start();
        //main线程,主线程
        for (int i = 0; i < 200; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }
}

案例改写

package com.hao.demo01;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,实现多线程同步下载图片
public class TestThread2 implements Runnable{

    private String url;//网络图片地址
    private String name;//保存的文件名
    public TestThread2(String url,String name){
        this.url=url;
        this.name=name;
    }

    //下载图片线程的执行体
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&fmt=auto&app=138&f=JPEG?w=632&h=500","1.jpg");
        TestThread2 t2 = new TestThread2("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
        TestThread2 t3 = new TestThread2("https://img0.baidu.com/it/u=1721391133,702358773&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=625","3.jpg");
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();

    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

小结

◆继承Thread类

  • 子类地承Thread类具备多线程能力

  • 启动线程:子类对象. start()

  • 不建议使用:避免OOP单继承局限性

◆实现Runnable接口

  • 实现接口Runnable具有多线程能力
  • 启动线程:传入目标对象+Thread对象.start()
  • 推荐使用:避免单继承局限性。灵活方便。方便同一个对象被多个线程使用

初识并发问题

以抢火车票为例子

package com.hao.demo01;

//多个线程同时操作同一个对象
// 买火车票的例子

public class TestThread4 implements Runnable{

    //票数
    private int ticketNums=10;
    @Override
    public void run() {
        while(true){
            if (ticketNums<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(200);//延时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 t = new TestThread4();
        new Thread(t,"小蜜蜂").start();
        new Thread(t,"小欣宇").start();
        new Thread(t,"小壮壮").start();
    }
}

程序运行结果:

image-20220328204623925

注意:

  • Thread.currentThread().getName()可以获得当前线程的名字
  • new Thread(run事件,线程名字)
  • 可以加一个延迟并捕获错误,防止某个小同学抢了所有的票
  • //发现问题:多个线程操作同一个资源的情况下,线程不安全了,数据紊乱

案例:龟兔赛跑——Race

有个兔子叫壮壮,有个乌龟叫毛毛,有一天他们心血来潮想要比赛

  1. 首先来个赛道距离,然后要离终点越来越近
  2. 判断比赛是否结束
  3. 打印出胜利者
  4. 龟兔赛跑开始
  5. 故事中是乌龟赢的,兔子需要唾觉:所以我们来模拟兔子睡觉
  6. 终于,乌龟赢得比赛
package com.hao.demo01;

//模拟龟兔赛跑
public class Race implements Runnable {
    //胜利者
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //模拟兔子休息
            if(Thread.currentThread().getName().equals("兔子壮壮")&& i%90==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
            //判断比赛是否结束
            boolean flag = gameover(i);
            //如果比赛结束了,就停止程序
            if(flag){
                break;
            }
        }
    }
    //判断是否完成比赛
    private boolean gameover(int steps){
        //判断是否有胜利者
        if(winner!=null){//已经存在胜利者
            return true;
        }{
            if (steps>=100){
                winner=Thread.currentThread().getName();
                System.out.println("winner is"+winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race,"乌龟毛毛").start();
        new Thread(race,"兔子壮壮").start();

    }
}

实现Callable接口(了解即可)

  • 实现Callable接口,需要返回值类型Callable(可以设置其他)
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1)
  • 提交执行:Future result1=ser.submit(t1);
  • 获取结果 boolean r1=result1.get()
  • 关闭服务:ser.shutdownNow();
package com.hao.demo02;

//线程创建方式三:实现callable接口

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//练习Thread,实现多线程同步下载图片
public class TestCallable implements Callable {

    private String url;//网络图片地址
    private String name;//保存的文件名
    public TestCallable(String url,String name){
        this.url=url;
        this.name=name;;
    }

    //下载图片线程的执行体
    @Override
    public Boolean call() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable t1 = new TestCallable("https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&fmt=auto&app=138&f=JPEG?w=632&h=500","1.jpg");
        TestCallable t2 = new TestCallable("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg");
        TestCallable t3 = new TestCallable("https://img0.baidu.com/it/u=1721391133,702358773&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=625","3.jpg");

        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(3);
        // 提交执行:
        Future result1=ser.submit(t1);
        Future result2=ser.submit(t2);
        Future result3=ser.submit(t3);
        // 获取结果
        boolean r1=result1.get();
        boolean r2=result3.get();
        boolean r3=result3.get();
        //关闭服务:
        ser.shutdownNow();


    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
}

静态代理

image-20220328214943970

package com.hao.demo02;

public class StaticProxy {
    public static void main(String[] args) {
        new WeddingCompany (new You()).HappyMarry();
        //WeddingCompany weddingCompany=new WeddingCompany(new You());
       // weddingCompany.HappyMarry();
    }

}
interface Marry{
    void HappyMarry();
}
//真实角色:你去结婚
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("要结婚了");
    }
}
//代理角色:帮你去结婚
class WeddingCompany implements Marry{
    //代理谁-->真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//这就是真实对象
        after();
    }

    private void after() {
        System.out.println("结婚之后,收尾款");
    }

    private void before() {
        System.out.println("结婚之前,布置现场");
    }
}

image-20220328220308497

总结:

  • 真实对象和代理对象都要事先同一个接口
  • 好处:代理对象可以做很多真实对象做不了的事情,真实对象专注自己的事情

image-20220328220949264

  • Thread的真实对象Runable接口,同时Thread也实现了Runable接口,HappyMarry相当于start,有共同的方法run方法

  • 多线程02

    Lamda表达式

    • \(\lambda\)希腊字母表中排序第十一位的字母,英语名称为Lambda

    image-20220329143920453

    • 避免匿名内部类定义过多
    • 其实质属于函数式编程的概念
    (params)->expression [表达式]
    (params)->statement [语句]
    (params)->{statements}
    

    a->System.out.println("i like lambda-->"+a)

    new Thread (()->System.out.print("多线程学习。。。")).start();
    
    • 为什么要使用Lambda表达式

      • 避免匿名内部类定义过多
      • 可以让你的代码看起来很简洁
      • 去掉了一堆没有意义的代码,只留下核心的逻辑
    • 理解Functional Interface (函数式接口)是学习Java8 lambda表达式的关键所在。

    • 函数式接口的定义:

      • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
      public interface Runnable{
          public abstract void run();
      }
      
      • 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

    优化前代码

    package com.hao.lambda;
    
    /*
    推到lambda表达式
     */
    public class TestLambda1 {
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
        }
    }
    //1.定义一个函数式接口
    interface ILike{
        void lambda();
    }
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    image-20220329145839432

    优化后代码1.0

    采用内部静态类

    package com.hao.lambda;
    
    /*
    推到lambda表达式
     */
    public class TestLambda1 {
        // 3. 静态内部类(把实现类,放到静态内部类中)
        static class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
    
            like=new Like2();
            like.lambda();
        }
    }
    //1.定义一个函数式接口
    interface ILike{
        void lambda();
    }
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    ![image-20220329145932022](F:\Program Files (x86)\Typora\image-20220329145932022.png)

    优化代码2.0

    采用局部内部类

    package com.hao.lambda;
    
    /*
    推到lambda表达式
     */
    public class TestLambda1 {
        // 3. 静态内部类(把实现类,放到静态内部类中)
        static class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
    
            like=new Like2();
            like.lambda();
    
            //4. 局部内部类(和上面放的位置不同)
            class Like3 implements ILike{
                @Override
                public void lambda() {
                    System.out.println("i like lambda3");
                }
            }
            like=new Like3();
            like.lambda();
        }
    }
    //1.定义一个函数式接口
    interface ILike{
        void lambda();
    }
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    image-20220329150323461

    优化代码3.0

    采用匿名内部类,没有类的名称,必须借助接口或者父类

    package com.hao.lambda;
    
    /*
    推到lambda表达式
     */
    public class TestLambda1 {
        // 3. 静态内部类(把实现类,放到静态内部类中)
        static class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
    
            like=new Like2();
            like.lambda();
    
            //4. 局部内部类(和上面放的位置不同)
            class Like3 implements ILike{
                @Override
                public void lambda() {
                    System.out.println("i like lambda3");
                }
            }
            like=new Like3();
            like.lambda();
    
            //5.匿名内部类(没有类的名称,必须借助接口或者父类)
            like = new ILike() {
                @Override
                public void lambda() {
                    System.out.println("i like lambda4");
                }
            };
            like.lambda();
        }
    }
    //1.定义一个函数式接口
    interface ILike{
        void lambda();
    }
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    image-20220329151015895

    优化代码4.0

    采用lambda简化

    package com.hao.lambda;
    
    /*
    推到lambda表达式
     */
    public class TestLambda1 {
        // 3. 静态内部类(把实现类,放到静态内部类中)
        static class Like2 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
        public static void main(String[] args) {
            ILike like = new Like();
            like.lambda();
    
            like=new Like2();
            like.lambda();
    
            //4. 局部内部类(和上面放的位置不同)
            class Like3 implements ILike{
                @Override
                public void lambda() {
                    System.out.println("i like lambda3");
                }
            }
            like=new Like3();
            like.lambda();
    
            //5.匿名内部类(没有类的名称,必须借助接口或者父类)
            like = new ILike() {
                @Override
                public void lambda() {
                    System.out.println("i like lambda4");
                }
            };
            like.lambda();
    
            //6.用lambda简化
            like=()->{
                System.out.println("i like lambda5");
            };
            like.lambda();
        }
    }
    //1.定义一个函数式接口
    interface ILike{
        void lambda();
    }
    //2.实现类
    class Like implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda");
        }
    }
    

    image-20220329151834235

    带参数的Lambda简化

    package com.hao.lambda;
    
    public class TestLambda2 {
    
        public static void main(String[] args) {
            ILove love =null;
            //1.lambda表达式简化
             love =(int a)->{
                    System.out.println("I love u-->"+a);
                };
            //简化1.参数类型
            love=(a)->{
                System.out.println("I love u-->"+a);
            };;
            //简化2.简化括号
            love=a->{
                System.out.println("I love u-->"+a);
            };
            //简化3.去掉花括号
            love=a->System.out.println("I love u-->"+a);
            love.love(521);
    
        }
    }
    interface ILove{
        void love(int a);
    }
    

    总结:

    • lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹
    • 必须前提是函数式接口,接口里只有一个方法
    • 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号

    扩展:

    Runnable接口如下图,发现只有一个方法,可以采用lambda的方法来简化代码!

    image-20220329154807091

Lamda表达式

  • \(\lambda\)希腊字母表中排序第十一位的字母,英语名称为Lambda

image-20220329143920453

  • 避免匿名内部类定义过多
  • 其实质属于函数式编程的概念
(params)->expression [表达式]
(params)->statement [语句]
(params)->{statements}

a->System.out.println("i like lambda-->"+a)

new Thread (()->System.out.print("多线程学习。。。")).start();
  • 为什么要使用Lambda表达式

    • 避免匿名内部类定义过多
    • 可以让你的代码看起来很简洁
    • 去掉了一堆没有意义的代码,只留下核心的逻辑
  • 理解Functional Interface (函数式接口)是学习Java8 lambda表达式的关键所在。

  • 函数式接口的定义:

    • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
    public interface Runnable{
        public abstract void run();
    }
    
    • 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

优化前代码

package com.hao.lambda;

/*
推到lambda表达式
 */
public class TestLambda1 {
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

image-20220329145839432

优化后代码1.0

采用内部静态类

package com.hao.lambda;

/*
推到lambda表达式
 */
public class TestLambda1 {
    // 3. 静态内部类(把实现类,放到静态内部类中)
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like=new Like2();
        like.lambda();
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

![image-20220329145932022](F:\Program Files (x86)\Typora\image-20220329145932022.png)

优化代码2.0

采用局部内部类

package com.hao.lambda;

/*
推到lambda表达式
 */
public class TestLambda1 {
    // 3. 静态内部类(把实现类,放到静态内部类中)
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4. 局部内部类(和上面放的位置不同)
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like=new Like3();
        like.lambda();
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

image-20220329150323461

优化代码3.0

采用匿名内部类,没有类的名称,必须借助接口或者父类

package com.hao.lambda;

/*
推到lambda表达式
 */
public class TestLambda1 {
    // 3. 静态内部类(把实现类,放到静态内部类中)
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4. 局部内部类(和上面放的位置不同)
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like=new Like3();
        like.lambda();

        //5.匿名内部类(没有类的名称,必须借助接口或者父类)
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

image-20220329151015895

优化代码4.0

采用lambda简化

package com.hao.lambda;

/*
推到lambda表达式
 */
public class TestLambda1 {
    // 3. 静态内部类(把实现类,放到静态内部类中)
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }
    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4. 局部内部类(和上面放的位置不同)
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like=new Like3();
        like.lambda();

        //5.匿名内部类(没有类的名称,必须借助接口或者父类)
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6.用lambda简化
        like=()->{
            System.out.println("i like lambda5");
        };
        like.lambda();
    }
}
//1.定义一个函数式接口
interface ILike{
    void lambda();
}
//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

image-20220329151834235

带参数的Lambda简化

package com.hao.lambda;

public class TestLambda2 {

    public static void main(String[] args) {
        ILove love =null;
        //1.lambda表达式简化
         love =(int a)->{
                System.out.println("I love u-->"+a);
            };
        //简化1.参数类型
        love=(a)->{
            System.out.println("I love u-->"+a);
        };;
        //简化2.简化括号
        love=a->{
            System.out.println("I love u-->"+a);
        };
        //简化3.去掉花括号
        love=a->System.out.println("I love u-->"+a);
        love.love(521);

    }
}
interface ILove{
    void love(int a);
}

总结:

  • lambda表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹
  • 必须前提是函数式接口,接口里只有一个方法
  • 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号

扩展:

Runnable接口如下图,发现只有一个方法,可以采用lambda的方法来简化代码!

image-20220329154807091