1.函数式编程思想概述
面向对象思想:
做一件事情,找一个能够解决这个事情的对象,调用对象的方法来完成这件事情
函数式编程思想:
重视的是结果,怎么做事情,不重视完成的过程,找谁来做
2.使用Lambda表达式简化匿名内部类
/*
使用Lambda表达式简化匿名内部类(重点)
*/
public class Demo01Lambda {
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()+"-->使用Lambda表达式的方式,实现多线程程序!");
}).start();
}
}
3.Lambda表达式的语法
基本使用格式:
( ) -> { }
// 一些参数,一个箭头,一些代码
- ():重写接口中唯一的抽象方法的参数列表,没有参数就空着,有多个参数使用逗号隔开
- ->:传递,可以把参数()传递给{ }方法体使用
- { }:重写接口中唯一抽象方法的方法体
Lambda表达式作用:简化匿名内部类
Lambda表达式的使用前提:
- 必须有接口
- 接口中有且只能仅有一个抽象方法(函数式接口)
注意:
- Lambda表达式是可推导可省略
- Lambda表达式的目的就是重写接口中唯一的抽象方法
- 接口中的抽象方法只有一个,可以推导出重写的就是接口唯一的这个抽象方法,所以代码才能使用lambda简化
4.使用Lambda表达式重写有参数有返回值的方法
import java.util.Arrays;
import java.util.Comparator;
/*
使用Lambda表达式重写有参数有返回值的方法(重点)
需求:
创建一个数组,数组的类型使用Person
创建3个Person对象,存储到数组中
使用数组工具类Arrays中的方法sort,根据比较器产生的规则对Person对象进行按照年龄升序排序
*/
public class Demo02Lambda {
public static void main(String[] args) {
//创建一个数组,数组的类型使用Person
Person[] arr = new Person[3];
//创建3个Person对象,存储到数组中
arr[0] = new Person("张三",18);
arr[1] = new Person("李四",20);
arr[2] = new Person("王五",19);
System.out.println("排序前数组中的元素:"+Arrays.toString(arr));
//使用数组工具类Arrays中的方法sort,根据比较器产生的规则对Person对象进行按照年龄升序排序
Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
//升序:o1-o2 降序:o2-o1
return o1.getAge()-o2.getAge();
}
});
System.out.println("排序后数组中的元素:"+Arrays.toString(arr));
//使用Lambda表达式简化匿名内部类 public int compare(Person o1, Person o2)
Arrays.sort(arr,(Person o1, Person o2)->{
return o2.getAge()-o1.getAge();
});
System.out.println("排序后数组中的元素:"+Arrays.toString(arr));
}
}
5.Lambda表达式简化格式
Lambda表达式是可推导可以省略的;
可以推导出,Lambda表达式重写的就是接口中唯一的抽象方法;
也可以推导出方法的参数和方法有没有返回值,可以对参数和返回值在进行简化
Lambda表达式的格式:
(参数列表) -> {重写抽象方法的方法体}
简化:
(参数列表):参数列表的数据类型是可以推导出来的,可以省略
(int a) ==> (a) (int a,String s) ==> (a,s)
(参数列表):参数列表中只有一个参数,()小括号也可以省略,但是参数列表没有参数,()小括号不能省略
(int a) ==> (a) ==> a
- {重写抽象方法的方法体}:重写的方法体,如果只有一行代码(java中行的以分号分隔开的),无论是否有返回值,中括号 { } 和一行代码的结束的分号( ; )和 return 关键字可以一起省略不写
注意:这三部分( { } ; return )或者这两部分( { } ; )必须一起省略
import java.util.Arrays;
import java.util.Comparator;
public class Demo03Lambda {
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()+"使用Lambda表达式的方式,实现多线程程序!");
}).start();
//简化Lambda表达式
new Thread(() -> System.out.println(Thread.currentThread().getName()+"使用简化Lambda表达式的方式,实现多线程程序!")).start();
System.out.println("-------------------------");
//创建一个数组,数组的类型使用Person
Person[] arr = new Person[3];
//创建3个Person对象,存储到数组中
arr[0] = new Person("张三",18);
arr[1] = new Person("李四",20);
arr[2] = new Person("王五",19);
System.out.println("排序前数组中的元素:"+ Arrays.toString(arr));
//使用数组工具类Arrays中的方法sort,根据比较器产生的规则对Person对象进行按照年龄升序排序
Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
//升序:o1-o2 降序:o2-o1
return o1.getAge()-o2.getAge();
}
});
System.out.println("排序后数组中的元素:"+Arrays.toString(arr));
//使用lambda表达式简化匿名内部类
Arrays.sort(arr,(Person o1, Person o2) -> {
return o1.getAge()-o2.getAge();
});
System.out.println("排序后数组中的元素:"+Arrays.toString(arr));
//简化Lambda表达式
Arrays.sort(arr,(o1, o2) -> o1.getAge()-o2.getAge());
}
}
方法引用
方法引入是JDK1.8出现的新特性,用于简化Lambda表达式。当一些内容已经存在了,就可以使用方法引用,直接引用这些已经存在的内容
1).对象名--引用成员方法
当对象和成员方法都是已经存在的时候,就可以使用对象名来直接引用成员方法
格式:
对象名::成员方法名 // :: 方法引用的运算符
import java.util.function.Supplier;
/*
java.util.function.Supplier<T>:函数式接口
接口中唯一的抽象方法:
T get() :用来获取一个接口指定泛型类型的数据
Supplier接口使用什么泛型,就可以使用get方法获取什么类型的数据
*/
public class Demo01 {
public static void main(String[] args) {
//调用method方法,方法的参数Supplier是一个函数式接口,所以我们可以使用Lambda表达式作为接口的实现类对象
method(()->{
//返回一个大写的字符串
String s = new String("abc");
return s.toUpperCase();
});
//简化Lambda表达式
method(()->new String("abc").toUpperCase());
/*
字符串对象"abc"是已经存在的
字符串中的方法toUpperCase也是已经存在的
使用字符串对象"abc"直接引用成员方法toUpperCase
对象名::引用成员方法
*/
method(new String("abc")::toUpperCase);
method("abc"::toUpperCase);
method("abc"::toLowerCase);
//method("abc"::show); //Cannot resolve method 'show' show方法在String类中不存在
}
/*
定义一个方法,方法的参数
使用Supplier接口,泛型使用String
方法内部使用Supplier接口中的get方法获取一个字符串
*/
public static void method(Supplier<String> sup){
String s = sup.get();
System.out.println(s);
}
}
2).类名--引用静态方法
如果类和静态成员方法是已经存在的,那么就可以使用类名直接引用静态成员方法
格式:
类名::引用静态成员方法
import java.util.function.Supplier;
public class Demo03 {
public static void main(String[] args) {
//调用method方法,方法的参数Supplier是一个函数式接口,所以我们可以使用Lambda表达式作为接口的实现类对象
method(()->{
//返回一个随机小数
return Math.random(); //[0.0-1.0)
});
//简化Lambda表达式
method(()-> Math.random());
/*
Math数学工具类是已经存在
random静态方法已经已经存在的
就可以直接使用Math类引用静态成员方法random,简化lambda
Math::random:也相当于Supplier接口的实现类对象
*/
method(Math::random);
}
/*
定义一个方法,方法的参数
使用Supplier接口,泛型使用Double
方法内部使用Supplier接口中的get方法获取一个小数
Supplier<Double> sup = Math::random;
*/
public static void method(Supplier<Double> sup){
Double d = sup.get();
System.out.println(d);
}
}
3).类--构造引用
如果类中的构造方法是已经存在的,使用构造方法直接引用new创建对象
格式:
构造方法::new // Person::new ==> 使用构造方法引用new创建对象
import java.util.function.Function;
/*
java.util.function.Function<T,R>:函数接口
接口中唯一的抽象方法:
R apply(T t) 根据参数类型T获取类型R类型的返回值,用于类型转换 T转换R
例如:
Function<String,Integer>:根据传递String类型的数据,获取Integer类型的结果 "123"==>123 = Integer.parseInt("123")
Function<String,Person>:根据传递String类型的数据,获取Person类型的结果 "小明"==>Person p = new Person("小明")
...
*/
public class Demo04 {
public static void main(String[] args) {
//调用method方法,方法的参数Function是一个函数式接口,所以我们可以使用Lambda表达式作为接口的实现类对象
method((String s)->{
return new Person(s);
},"小明");
//简化Lambda表达式
method(s -> new Person(s),"小红");
/*
Lambda表达式的目的:根据字符串的姓名,创建Person对象返回
创建Person对象的构造方法是已经存在的public Person(String name)
创建对象使用的关键字new已经存在的
所以就可以使用构造方法引用new关键字直接创建对象
构造方法::new
*/
method(Person::new,"邓丽君");
}
/*
定义一个方法,方法的参数
使用Function接口,泛型使用<String,Person>
传递一个字符串
在方法内部使用Function接口中的方法apply,把字符串转换为Person对象返回
*/
public static void method(Function<String,Person> fun,String s){
Person p = fun.apply(s);
System.out.println(p);
}
}
4).数组--构造引用
格式:
数组的数据类型[]::new // int[]::new 创建一个int类型的数组 int[] arr = new int[10];
import java.util.Arrays;
import java.util.function.Function;
public class Demo05 {
public static void main(String[] args) {
//调用method方法,方法的参数Function是一个函数式接口,所以我们可以使用Lambda表达式作为接口的实现类对象
method((Integer len)->{
//根据数组的长度,创建一个指定长度的数组返回
return new int[len];
},10);
//简化Lambda表达式
method(len->new int[len],10);
/*
Lambda表达式目的:创建一个指定长度的数组 new int[len]
数组的数据类型已经存在的int
数组的长度已经存在的len
使用方法引用简化Lambda表达式
使用int[]引用关键字new,根据数组的长度创建指定长度的数组返回
int[]::new
*/
method(int[]::new,10);
}
/*
定义一个方法,方法的参数
使用Function接口,泛型使用<Integer,int[]>
传递int类型数组的长度
在方法内部,使用Function接口中的方法apply,根据传递的数组长度,创建一个指定长度的数组返回
*/
public static void method(Function<Integer,int[]> fun,int length){
int[] arr = fun.apply(length);
System.out.println(Arrays.toString(arr));
}
}
5).方法引用在Stream流中的使用(常用)
import java.util.stream.Stream;
public class Demo06Stream {
public static void main(String[] args) {
//获取一个Stream流
Stream<String> stream = Stream.of("a", "b", "c");
//使用forEach方法遍历Stream流
//stream.forEach(s-> System.out.println(s));
//使用方法引用简化Lambda表达式
stream.forEach(System.out::println);
}
}
函数式接口
1.函数式接口的定义
函数式接口:接口中有且仅有一个抽象方法的接口
函数式接口一般都作为方法的参数(另外也可以作为返回值类型)
- 方法的参数是一个函数式接口,那么就可以传递lambda表达式作为接口的一种实现类对象为方法的参数接口变量进行赋值
- 方法的返回值类型是一个函数式接口,方法内部就可以返回一个Lambda表达式作为接口的实现类对象
注意:
- 接口中没有抽象方法不行
- 接口中除了唯一的抽象方法,还可以包含其他的方法(默认,静态,私有)
@FunctionalInterface // 注解@FunctionalInterface:检测接口是否为一个函数式接口
public interface MyFunction {
//定义抽象方法
public abstract void show(int a);
public static void show02(){
System.out.println("静态方法!");
}
public default void show03(){
System.out.println("默认方法!");
}
}
2.函数式接口的使用
函数式接口的使用:和使用普通的接口是一样的用法
- 在工作中,一般都使用函数式接口作为方法的参数类型或者返回值类型使用
- 调用方法传递的参数和方法返回的值,就可以使用Lambda表达式来简化了
- Lambda表达式可以看成就是接口实现类对象的一种
public class Demo01MyFunction {
public static void main(String[] args) {
//调用method方法,方法的参数MyFunction是一个接口,可以传递接口的实现类对象,给接口变量赋值
method(new MyFunction() {
@Override
public void show(int a) {
System.out.println("匿名内部类的方式,重写show方法-->"+a);
}
},10);
//调用method方法,方法的参数MyFunction是一个函数式接口,可以传递接口的实现类对象,给接口变量赋值
//使用Lambda表达式作为接口的实现类对象
method((int a)->{
System.out.println("Lambda表达式的方式,重写show方法-->"+a);
},10);
//简化lambda表达式
method(a->System.out.println("Lambda表达式的方式,重写show方法-->"+a),10);
System.out.println("------------------------------");
//多态 接口 = 实现类对象
//MyFunction my = a->System.out.println("方法返回的是一个Lamda表达式:"+a);
MyFunction my = getInstance();
my.show(100);
}
/*
定义一个方法,方法的参数类型使用函数式接口MyFunction
//多态 接口 匿名内部类对象
MyFunction my = new MyFunction() {
@Override
public void show(int a) {
System.out.println("匿名内部类的方式,重写show方法-->"+a);
}
};
------------------
MyFunction my = (int a)->{
System.out.println("Lambda表达式的方式,重写show方法-->"+a);
}
*/
public static void method(MyFunction my,int i){
my.show(i);
}
/*
定义一个方法,方法的返回值类型使用函数式接口MyFunction
*/
public static MyFunction getInstance(){
//方法的返回值类型是MyFunction接口,方法就需要返回一个MyFunction接口的实现类对象
/*return new MyFunction() {
@Override
public void show(int a) {
System.out.println("方法返回的是一个匿名内部类对象:"+a);
}
};*/
//方法的返回值类型是MyFunction函数式接口,方法就需要返回一个Lambda表达式作为MyFunction接口的实现类对象
/*return (int a)->{
System.out.println("方法返回的是一个Lamda表达式:"+a);
};*/
//简化lambda表达式
return a->System.out.println("方法返回的是一个Lamda表达式:"+a);
}
}
3.函数式接口:Consumer
java.util.function.Consumer:函数式接口-消费者
接口中唯一的抽象方法:
void accept(T t) //消费一个指定泛型类型的数据
Consumer接口的泛型使用什么类型,就可以使用accept方法消费(使用)一个什么类型的数据
至于我们怎么使用这个数据,看心情(想怎么使用就怎么使用,可以计算,可以输出...)
import java.util.function.Consumer;
public class Demo02Consumer {
public static void main(String[] args) {
//调用method方法,方法的参数Consumer是一个接口,可以传递接口的匿名内部类对象,给接口变量赋值
method(new Consumer<String>() {
@Override
public void accept(String s) {
//怎么使用这个参数,看心情
System.out.println(s);
}
},"aaa");
//调用method方法,方法的参数Consumer是一个函数式接口,可以传递lambda表达式作为接口的实现类对象,给接口变量赋值
method((String s)->{
System.out.println(s);
},"abc");
//简化Lambda表达式
method(s-> System.out.println(s),"cba");
}
/*
定义一个方法,方法的参数
使用Consumer接口,泛型使用String
使用一个字符串参数
在方法的内部使用Consumer接口中的方法accept,对字符串参数进行消费
*/
public static void method(Consumer<String> con,String s){
con.accept(s);
}
}
4.函数式接口:Supplier
java.util.function.Supplier:函数式接口-供应商
接口中唯一的抽象方法:
T get() // 用来获取接口指定泛型类型的数据
Supplier接口使用什么泛型,就可以使用get方法获取一个什么类型的数据
import java.util.Random;
import java.util.function.Supplier;
public class Demo05Supplier {
public static void main(String[] args) {
//调用method方法,方法的参数Supplier是一个接口,可以传递接口的匿名内部类对象,给接口变量赋值
method(new Supplier<Integer>() {
@Override
public Integer get() {
return 10;
}
});
//调用method方法,方法的参数Supplier是一个函数式接口,可以传递lambda表达式作为接口的实现类对象,给接口变量赋值
method(() -> {
return 10;
});
//简化Lambda表达式
method(() -> 10);
method(() -> new Random().nextInt(100));
}
/*
定义一个方法,方法的参数
使用Supplier接口,接口的泛型使用Integer
在方法内部使用Supplier接口中的get方法,获取一个Integer类型的数据返回
*/
public static void method(Supplier<Integer> sup){
Integer in = sup.get();
System.out.println(in);
}
}
5.函数式接口:Predicate
java.util.function.Predicate:函数式接口-类型判断
接口中唯一的抽象方法:
boolean test(T t) //用于对接口指定泛型类型的数据进行判断
Predicate接口的泛型使用什么类型,就可以使用test方法判断数据是否满足要求
- 满足要求:返回true
- 不满足安全:返回false
import java.util.function.Predicate;
public class Demo03Predicate {
public static void main(String[] args) {
//调用method方法,方法的参数Predicate是一个接口,可以传递接口的匿名内部类对象,给接口变量赋值
method(new Predicate<String>() {
@Override
public boolean test(String s) {
//判断的规则:判断字符串的长度是否大于5
return s.length()>5;
}
},"aaa");
//调用method方法,方法的参数Predicate是一个函数式接口,可以传递lambda表达式作为接口的实现类对象,给接口变量赋值
method((String s) -> {
return s.length()>5;
},"aaaaaa");
//简化Lambda表达式
method(s -> s.length()>5,"1111");
}
/*
定义一个方法,方法的参数
使用Predicate接口,泛型使用String
使用String类型的参数
在方法内部使用Predicate接口中的方法test对字符串进行判断,是否满足要求
*/
public static void method(Predicate<String> pre,String s){
boolean b = pre.test(s);
System.out.println(b);
}
}
6.函数式接口:Function
java.util.function.Function<T,R>:函数接口-类型转换
接口中唯一的抽象方法:
R apply(T t) //根据参数类型T获取类型R类型的返回值,用于类型转换 T转换R
例如:
// 根据传递String类型的数据,获取Integer类型的结果 "123" ==> 123 = Integer.parseInt("123")
Function<String, Integer>
// 根据传递String类型的数据,获取Person类型的结果 "小明" ==> Person p = new Person("小明")
Function<String, Person>
import java.util.function.Function;
public class Demo04Function {
public static void main(String[] args) {
//调用method方法,方法的参数Function是一个接口,可以传递接口的匿名内部类对象,给接口变量赋值
method(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
//把字符串整数,转换为Integer类型返回
return Integer.parseInt(s);
}
},"10");
//调用method方法,方法的参数Function是一个函数式接口,可以传递lambda表达式作为接口的实现类对象,给接口变量赋值
method((String s)->{
return Integer.parseInt(s);
},"20");
//简化Lambda表达式
method(s->Integer.parseInt(s),"30");
}
/*
定义一个方法,方法的参数
使用Function接口,接口的泛型使用<String,Integer>
使用一个String类型的参数
在方法内部使用Function接口中的方法apply,把String类型的数据转换为Integer类型返回
*/
public static void method(Function<String,Integer> fun,String s){
Integer in = fun.apply(s);
System.out.println(in+100);
}
}