一,函数式接口
1.1概念
函数是借口在Java中指的是:有且仅有一个抽象方法的接口。而Java中的函数式编程体现就是lambda,所以函数式接口就是可以使用于lambda的接口,只有确保接口中只有一个抽象方法,Java中的lambda才能顺利的进行推导。
备注:语法糖是指的是为了使用更加方便,但原理不变的代码语法。例如for循环和增强for循环。从应用层面来看lambda可以看作是匿名内部类的语法糖,但是他们的原理其实是不同的。
1.2格式
只要确保接口里面有且只有一个抽象方法就可以了。接口里面可以有默认方法,私有方法,静态方法。
1.3 @FunctionalInterface
注解:@FunctionalInterface作用是检测该接口是否是函数式接口。如果不是就会报错。
使用:一般作为函数的参数和返回值类型来使用。之前课程里面讲过
二,函数式编程
2.1 lambda的延迟执行
有些代码执行后,结果不一定会被使用,从而造成了性能上的浪费。而lambda在执行上是延迟的,这正好可以作为解决方法提升性能。
性能浪费问题的日志案例
注意:日志可以帮助我们快速的定位问题,记录程序运行中的问题,以遍项目的管理和优化。
直接打印
当等级不是一的时候讲道理不需要拼接字符串但是这里还是会先拼接所以这里的代码存在性能问题
package lambda;
public class Logger {
public static void main(String[] args) {
// TODO Auto-generated method stub
String message1 = "hello";
String message2 = "world";
show(1,message1+message2);
}
public static void show(int level,String message) {
if (level==1) {
System.out.println(message);
}
}
}
利用lambda优化日志打印
只有满足条件了才执行这也就是他的延迟执行的特性
package lambda;
public class Lambda {
public static void main(String[] args) {
// TODO Auto-generated method stub
String message1 = "hello";
String message2 ="world";
show(1,()->{
return message1+message2;
});
}
public static void show(int level, MyInterface mf) {
if(level==1) {
System.out.println(mf.buildMessage());
}
}
}
2.2使用lambda作为参数和返回值
如果抛开远离不说,Java的lambda表达式可以看作是匿名内部类的替代品。假如方法的参数是一个函数式接口,那么就可以使用lambda表达式进行替代,使用lamba 表达式做为方法的参数,其实就是使用函数式方法作为方法参数。
假如Java.lang.Runnable 接口就是一个函数接口,假如有一个startThread方法使用该接口作为参数,那么就可以使用lambda进行传参,这种情况其实和Thread类的构造方法参数设置为Runnable没有本质的区别。
- 函数式接口作为方法的参数
public class FunctionalInterface{
public static startThread(Runnable run){
new Thread(run).start();
}
public static void main(String[] args){
startThread(new Runnable(){
@Overide
public void run(){
System.Out.println(Thread.currnetThread.getName())
}
});
}
}
利用lambda表达式来代替匿名内部类
public class FunctionalInterface{
public static startThread(Runnable run){
new Thread(run).start();
}
public static void main(String[] args){
startThread(()->{System.Out.println(Thread.currentThread.getName);});
}
}
- 函数式接口作为方法的返回值
思考一下这个返回的接口应该要怎么使用呀
public class FunctionalInterface{
public static void main(String[] args){
}
public static Comparator<Strin g> getComparator(){
return new Comparat
or<String>(){
@Override
public void -compare(String o1,String o2){
return o2.length()-o1.length();
}
}
}
}
利用lambda来优化
public class FunctionalInterface{
public static void main(String[] args){
//创建一个字符串数组
String[] s ={"ssssss","sssf","as"}
Arrays.sort(s,getComparator())
//这里的参数是一个数组和一个接口其实接口就是排序的标准,可以用匿名内部类来写也可以使用lambda使得接口作为返回值
public static Comparator<Strin g> getComparator(){
return (String o1,String o2)->{
return o2.length() - o1.length();
};//优化lambda首先可以去掉类型,然后只有一行代码我们可以省略掉大括号和分号
}
}
三,常用函数式接口
放在Java.util.function
3.1 Suplier接口
Java.util.function.Suppie 接口仅包含一个无参的方法,T get() 方法。用来获取一个泛型参数来指定类型的数据对象。由于只是一个函数式接口这意味着对应的lambda需要提供一个符合泛型类型的对象数据
Suppie 被称为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法也是返回什么类型的数据
抽象方法get其实就是返回数据
public class function{
public static String (Supplier sup){
return sup.get();
}
public static main(String[] args){
String s = getString(()->{
return "胡歌";
});//这里应该怎么用匿名内部类来重新写
}
}
public class function{
public static String (Supplier sup){
return sup.get();
}
public static main(String[] args){
String s = getString(()->
return "胡歌"//删掉大括号和分号来进行优化。
);//这里应该怎么用匿名内部类来重新写
}
}
3.2 使用Supplier来计算最大值
package suppier;
import java.util.function.Supplier;
public class Lambda {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = {1,2,3,10};
int maxvalue = getMax(()->{
int max = arr[0];
for(int i:arr) {
if(i>max) {
max=i;
}
}
return max;
});
System.out.println(maxvalue);
}
public static int getMax(Supplier<Integer> sup) {
return sup.get();
//如果不用lambda应该要怎么做呢?
下面这个代码其实是不对的
package suppier;
import java.util.function.Supplier;
public class Annoymounce {
public static void main(String[] args) {
int[] arr = {1,2,3,10};
int maxvalue = getMax(new Supplier() {
@Override
public Integer get(int[] arr) {
return arr[0];
}
});
}
public static int getMax(Supplier<Integer> sup) {
return sup.get();
}
}
3.3 Consumer接口
它是一个消费性接口怎么消费自定义,消费的意思就是对数据进行操作然后返回
抽象方法方法accept
package suppier;
import java.util.function.Consumer;
public class Consumer {
public static void main(String[] args) {
// TODO Auto-generated method stub
consumer("科比",(String name)->{
System.Out.println(name);
});
}
public static void consumer(String name, Consumer<String> con) {
con.accept(name);
}
}
默认方法andThen
可以把两个accept 方法连接在一起。
con1.accept();
con2.accept();
//等价于下面的一行代码
con1.andThen(con2).accept();
3.4格式化打印信息。
package suppier;
public class PrintInfo {
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] arr = {"地理二八,18","是田浩二,10"};
printIofo(arr,(message)->{
String name = message.split(",")[0];
System.Out.print(name);
},(message)->{
String age = message.split(",")[1];
System.Outprint(age);
});
}
public static void printInfo(String[] arr,Consumer<String> con1,Consumer<String> con2) {
for(String message:arr) {
con1.andThen(con2).accept(message);
}
}
}
3.5 Predicate 接口
有些时候我们需要对某种类型的数据进行判断,从而得到一个Boolean值的结果这时可以使用Java.util.function.Predicate接口
抽象方法test
package suppier;
import java.util.function.Predicate;
public class Predict {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "addff";
boolean flag = checkString(s,(String str) ->{
return str.length()>3;
});
System.out.println(flag);
}
public static boolean checkString(String s, Predicate<String> pre) {
return pre.test(s);
}
}
默认方法and or negate(取反)
package suppier;
import java.util.function.Predicate;
public class PredicateAnd {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s ="ssss";
boolean flag =checkString(s,(String message)->{return message.length()>3;},(String message)->{return message.contains("a");});
System.out.println(flag);
}
public static boolean checkString(String message, Predicate<String>p1,Predicate<String>p2) {
return p1.test(message) && p2.test(message);
//return p1.and(p2).test(message)
}
}
3.6集合信息的筛选
package suppier;
import java.util.ArrayList;
import java.util.function.Predicate;
public class Filter {
public static void main(String[] args) {
String[] famous = {"迪丽热巴,119","杨幂,20"};
ArrayList<String> path = filter(famous,(message)->{
String name = message.split(",")[0];
return name.length()==4;
},(message)->{
String age = message.split(",")[1];
return age.equals("119");
});
System.out.println(path.toString());
}
public static ArrayList<String> filter(String[] arr,Predicate<String> p1,Predicate<String> p2){
ArrayList<String> result = new ArrayList<>();
for(String s:arr){
boolean flag = p1.and(p2).test(s);
if(flag) {
result.add(s);
}
}
return result;
}
}
3.7 Function接口
用来根据一个数据类型得到另外一个数据类型,前者称之为前置条件后者称之为后置条件
Function<T,R>有两个泛型将数据T转化为R
抽象方法:apply
public static void change(String s,Function<String,Integer) fun{
int n=fun.apply(s);
System.Out.println(n);
}
public static void main(String[] args){
String s = "1234";
change(s,(String s)->{
return Integer.parseInt(s);
}
);
}
默认方法andThen 跟之前学过的那个差不多
package suppier;
import java.util.function.Function;
public class FunctionInterface {
//需要注意如果函数定义为空那么一定不可以返回值否则会报错的
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "1234";
change(s,(String str)->{
return Integer.parseInt(str)+10;
},(Integer i)->{
return i +"";
});
}
public static void change(String s,Function<String,Integer> fun1,Function<Integer,String> fun2) {
String result = fun1.andThen(fun2).apply(s);
System.out.println(result);
}
}
3.8 自定义函数模型的拼接
package suppier;
import java.util.function.Function;
public class Function3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "赵丽颖,19";
change( s, (String message)->{
return message.split(",")[1];
},(String str)->{
return Integer.parseInt(str);},
(Integer i)->{
return i + 10;
});
}
public static void change(String s, Function<String,String> fun1, Function<String,Integer> fun2, Function<Integer,Integer> fun3) {
int result = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(result);
}
}