面向对象编程 是对数据进行抽象,而函数式编程是对【行为进行抽象】。
通过函数式编程,程序员能编写出更容易阅读的代码,
这种代码更多地表达了业务逻辑,而不是从机制上如何实现。
从 函数式编程思想的角度去思考问题 ,最重要的就是 函数的输入和输出;
函数式编程思想改变了代码结构,将注重点放在了参数和返回值上。
函数式编程思想,通过使用一个 不可变值 和 函数,
函数对这个值进行处理,映射成另一个【任意的】【函数式接口类型的】值
1)概念:
函数式接口就是只定义**【一个抽象方法】**的接口。
注 : 哪怕这个接口中有很多默认 / 静态方法,
只要在这个接口中只定义了一个抽象方法 , 它就是一个函数式接口。
2)函数式接口的作用:
Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,
并把整个表达式作为函数式接口的实例。
用匿名内部类也可以完成同样的事情,只不过比较笨拙。
eg : Comparator c = Lambda表达式
TreeSet t = new TreeSet(c);
3) 函数描述符
函数式接口中的抽象方法的名基本上就是Lambda表达式的名,
我们将这种抽象方法叫作函数描述符。
4)声明函数式接口: `@FunctionalInterface`
这个标注用于表示该接口会设计成一个函数式接口
如果不满足函数式接口,会报错
5)java常用的函数式编程接口使用:
i. 比较器
ii. 实现线程
iii. 绑定事件
iv. 集合数据排序
JDK 1.8 API中包含了很多内建的函数式接口,
在老Java中常用到的比如Comparator或者Runnable接口,
这些接口都增加了@FunctionalInterface注解以便能用在lambda上。
Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便,
使用函数式编程接口,配合lambda表达式,可以以更少的代码为API方法添加更多的动态行为。
**java.util.function包下的常用函数式接口**
1)Predicate 接口
抽象方法: boolean = test(T t)
参数列表: 泛型T对象(泛型必须要传入一个包装器类型的数据)
返回值类型: boolean。
功能:可以通过这个抽象方法结合Lambda表达式,自定义一个判断规则,
对传入的对象进行判断
/**
* 把集合中满足要求的数据,进行打印
* 要求不确定,每次代码的要求可能都不一样
* @author Charlie
* 可以提供一个遍历筛选的方法,然后将要进行筛选的集合 以及 判断器 传入这个方法
* 这样只需要调用这个方法,然后每次传入的判断器不同,得到的筛选结果也不同
*/
public class Test4 {
public static void show(List<String> list,Predicate<String> pre) {
//遍历集合,把每个元素进程判断是否满足要求
for (String msg : list) {
//判断本次msg是否满足要求
boolean test = pre.test(msg);
if(test) {
System.out.println(msg);
}
}
}
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<String>();
list.add("Wendy");
list.add("Charlie");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("zhaosan");
//构建接口实现类对象
//由于本次接口为函数式接口,所以可以使用lambda表达式写
Predicate<String> p = (msg)->{return true;}; //获取所有的
Predicate<String> p1 = (msg)->{
return msg.length() > 5; //获取字符串长度大于5的
};
//Predicate p11 = (msg)-> msg.length() > 5; //简写
show(list,p);
System.out.println("------------------");
show(list,p1);
System.out.println("------------------");
//返回"z"开头的集合元素
Predicate<String> p2 = (msg)->{
//return (msg.charAt(0) == 'z');
return (msg.startsWith("z"));
};
show(list,p2);
System.out.println("------------------");
//返回"u"结尾的集合元素
Predicate<String> p21 = (msg)->{
return msg.endsWith("u");
};
show(list,p21);
System.out.println("------------------");
}
}
输出结果:
Wendy
Charlie
lisi
wangwu
zhaoliu
zhaosan
------------------
Charlie
wangwu
zhaoliu
zhaosan
------------------
zhaoliu
zhaosan
------------------
wangwu
zhaoliu
------------------
** Predicate接口还有几个默认方法 and 、 or 、~ … **
// and方法:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other); //判断后面的other是否为空
return (t) -> test(t) && other.test(t);
}
return (t) -> { return test(t) && other.test(t);};
}
// or方法
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
return (t) -> { test(t) || other.test(t); };
}
// negate方法
default Predicate<T> negate() {
return (t) -> !test(t);
}
测试and 、or方法:
//返回以"z"开头的集合元素,且以"u"结尾的集合元素
Predicate<String> p3 = p21.and(p2);
show(list,p3);
System.out.println("------------------");
//返回以"z"开头的集合元素,且以"u"结尾的集合元素,或者长度大于5的
Predicate<String> p4 = p1.or(p3);
show(list,p4);
测试结果:
zhaoliu
------------------
Charlie
wangwu
zhaoliu
zhaosan
2)Function 接口
抽象方法: R apply(T t);
参数列表: 泛型 T
返回值类型: 泛型 R
功能:可以通过这个抽象方法结合Lambda表达式,自定义一个功能,
对传入的对象执行一系列方法,产生结果
eg:
public class Test5 {
public static void show(List<String> list,Function<String,Integer> f) {
for (String msg : list) {
//将msg交给Function接口下的处理方法
//处理完以后返回一个数据
//这个数据被打印
Integer apply = f.apply(msg);
System.out.println(apply);
}
}
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<String>();
list.add("Wendy");
list.add("Charlie");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("zhaosan");
// R apply(T t);
Function<String,Integer> f = (String msg)->{
return msg.length();
};
show(list,f);
}
}
测试结果:
5
7
4
6
7
7
3) Supplier 接口
抽象方法: T get();
没有参数
返回值类型: 泛型 T
功能:提供一个 T (供应者)
eg:生成一个8位的随机验证码
> 使用Random随机生成
public class Test6 {
public static void main(String[] args) throws Exception {
Supplier<String> su = () -> {
//验证码能出现的字符,都在msg中定义
String msg = "ABCDEFGHHIJKLMNOPQRSTUVXWYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuffer sb = new StringBuffer(); //用来生成随机验证码
Random r = new Random(); //产生随机数
for (int i = 0; i < 8; i++) {
//随机获取msg中某一个位置的字符
int index = r.nextInt(msg.length());
sb.append(msg.charAt(index));
}
return sb.toString();
};
System.out.println(su.get());
System.out.println(su.get());
System.out.println(su.get());
System.out.println(su.get());
}
}
> 使用UUID类随机生成
//供应一个8位随机码
Supplier<String> s1 = ()->{
UUID uuid = UUID.randomUUID();
String msg = uuid.toString().substring(0,8);
return msg;
};
//调用接口中的方法完成功能,获得随机数
System.out.println(s1.get());
System.out.println(s1.get());
System.out.println(s1.get());
System.out.println(s1.get());
System.out.println(s1.get());
4)Consumer 接口
抽象方法: void accept(T t);
参数列表: 泛型 T
返回值类型: void
功能:对给定的参数执行此操作
public class Test7 {
public static void show(List<String> list,Consumer<String> c) {
for (String msg : list) {
//交给接口中的方法进行处理
c.accept(msg);
}
}
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<String>();
list.add("Wendy");
list.add("Charlie");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("zhaosan");
Consumer<String> c = (msg)->{
System.out.println("操作");
System.out.println(msg.substring(1));
System.out.println(msg.toUpperCase());
};
show(list,c);
//show(list,System.out::println);
}
}
5)BiFunction 接口
抽象方法: R apply(T t, U u)
参数列表: 泛型 T、泛型 U
返回值类型: 泛型 R
功能:将一个T和一个U输入,返回一个R作为输出
6)BinaryOperator 接口
抽象方法: T apply(T t, T t)
参数列表: 两个相同泛型的 T
返回值类型: 泛型 T
功能:将两个T作为输入,返回一个T作为输出
BinaryOperator接口继承了BiFunction接口
7)BiConsumer 接口
抽象方法: void accept(T t, U u)
参数列表: 泛型T、泛型U
没有返回值
功能:将俩个参数传入,执行操作
类型推断可以进一步简化你的代码。
Java编译器会从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式,
这意味着它也可以推断出适合Lambda的签名,因为函数描述符可以通过目标类型来得到。
这样做的好处在于,编译器可以了解Lambda表达式的参数类型,
这样就可以在Lambda语法中省去标注参数类型。
eg :
1)在集合中的类型推断
List<String> list = new ArrayList<>();
2)在lambda表达式中的类型推断
public void static void main(String[] args) {
// R apply(T t);
Function<String,Boolean> fun = (msg) -> {return msg == "tom"; };
//会自动推断出 需要传入一个String类型的参数,
//需要返回一个boolean类型的数据
}