3.线程匿名内部类实现
通常,我们也习惯用匿名内部类的方式创建并启动线程
通过下面示例会发现:Thread是个普通类,可以用匿名内部类,Runnable是个接口他也可以使用匿名内部类创建。
@Test public void test3(){ new Thread(){ //线程实现匿名内部类, new Thread(){Ctrl+H} @Override public void run() { System.out.println(Thread.currentThread().getName()+"创建线程1"); } }.start(); //开启线程 Runnable runnable = new Runnable() { // 利用Runnable开启线程 @Override public void run() { System.out.println(Thread.currentThread().getName() + "创建线程2"); } }; new Thread(runnable).start(); //开启线程 }
(三)、函数式(Function)接口
1.函数式接口概述
什么是函数式(Functional)接口
函数式接口就是只有一个方法的接口,同时,只有函数式接口可以使用Lambda表达式。
在java.util.function包下定义了Java 8 的丰富的函数式接口
Java当中的lambda是函数式编程吗
在函数式编程语言当中,Lambda表达式的类型是函数。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。
2.经典函数式接口
Runnable接口就是一个典型的函数式接口,在上面创建线程的时候也用到了,他是可以用 匿名内部类 的形式进行实例化的。
Runable是一个典型的函数式接口
@FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); } new Thread(()-> System.out.println(Thread.currentThread().getId()+"<-当前的线程名字")).start(); Runnable runnable = () -> { System.out.println(Thread.currentThread().getId()); };
3.自定义函数式接口
package com.example.springboot01hello.dao; @FunctionalInterface //表明我们这里是函数式接口,可设可不设。设置的话会提升性能 public interface interface1 { void show(); }
函数式接口中使用泛型:
package com.example.springboot01hello.dao; @FunctionalInterface //表明我们这里是函数式接口,可设可不设。设置的话会提升性能 public interface interface1<T> { public T show(T t); }
4.@FunctionlInterface用法
- 该注解只能标记在"有且仅有一个方法"的接口上,表示函数式接口。
- 该注解不是必须的,如果一个接口符合"函数式编程"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查,如果编写的不是函数式接口,但是加上了@Functionallnterface 那么编译器会报错。
- 在函数式接口使用该注解,javadoc 也会包含一条声明,说明这个接口是一个函数式接口
5.四大核心函数式接口
特别重要!!!
6.其他函数式接口
(四)、Lambda表达式
1. Lambda表达式概述
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。
Lambda表达式 和 函数式接口 的关系
Lambda表达式就是一个函数式接口的实例(注意是实例,Object a = new Object()这个a只是个引用变量,而new Object这是一个实例)。只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
Lambda表达式 和 匿名内部类 的关系
函数式接口是可以使用匿名内部类进行创建实例,而lambda可以简化使用匿名内部类创建。
注意: 使用lambda简化匿名内部类的前提条件是,接口必须是函数式接口。而匿名内部类创建实例却不一定非得是函数式接口,甚至都不一定是接口,还可以是普通类。
匿名内部类、函数式接口、lambda表达式 这三个关系一定要搞清楚。
2.Lambda 语法
Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符
为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
- 左侧:指定了 Lambda 表达式需要的参数列表
- 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能。
3.匿名内部类 转换 Lambda
从匿名类到 Lambda 的转换举例1:
通过下面示例我们能发现一个问题:使用匿名内部类,没有变量引用也可以创建,而lambda则不可以,他必须要有变量引用。这个变量引用可以是直接的变量引用,也可以是方法内参数传递,Lambda表达式就是一个函数式接口的实例。
注意俩字 “实列”!!!!!!
假如没有变量引用例如:
() -> System.out.println("我是一个函数式");
只有这个肯定是不行的,需要靠前面的TestInterface变量引用来做类型推断。
@Test public void test3() { interface1 interface0 = new interface1() { @Override public void show() { System.out.println("我是匿名内部类函数"); } }; interface0.show(); interface1 interface2 = () -> { System.out.println("我是Lambda表达式"); }; interface2.show(); }
4.匿名内部类 转换 Lambda 2
通过下面这个示例会发现,他其实就是在不断的优化,尽可能的让我们开发人员少写代码。他是如何做到一步一步省略的?其实这就是Java语法糖。
@Test public void test3() { // 1.匿名内部类创建线程 Runnable runnable = new Runnable() { // 利用Runnable开启线程 @Override public void run() { System.out.println(Thread.currentThread().getName() + "创建线程1"); } }; new Thread(runnable).start(); //开启线程 // 2.省去Runnable变量,等同于上方 new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "创建线程2"); } }).start(); //开启线程 // 3.使用Lambda表达式,实现多线程,省去了new Runnable和重写的方法名字 new Thread(() -> { System.out.println(Thread.currentThread().getName() + "创建线程3"); }).start(); // 4.优化Lambda,去掉大括号 new Thread(() -> System.out.println(Thread.currentThread().getName() + "创建线程3")).start(); }
5.Lambda语法格式
代码说明:使用Lambda表达式。一般的格式是()-> 0,如果0里面只有一行代码,则0可以省略。
->左边的()表示参数列表,
如果有形参,则在()中添加形参,->右边0表示具体逻辑
。如果方法体返回值是void,则甚至可以在0中不写任何逻辑(当然也要结合场景)。返回值如果有值,则需要写具体的逻辑, return处理后的值。