一,概述
1,函数式接口:有且只有一个抽象方法的接口,可以用其他方法(静态、默认、私有)。
2,@FunctionalInterface注解:在接口上添加,可用于检测接口是否是一个函数式接口。是则编译成功,否则编译失败(无抽象方法或抽象方法多余一个)。
3,函数式接口的使用:一般可以作为方法的参数和返回值类型。若有用到函数式接口,则可用Lambda表达式。
@FunctionalInterface
public interface DemoFuntionalInterface {
public abstract void method1();
}
public class DemoTest {
public static void main(String[] args) {
show(new DemoFuntionalImpl());
show(new DemoFuntionalInterface() {
@Override
public void method1() {
System.out.println("匿名内部类中的method方法..");
}
});
show( ()->System.out.println("Lambda表达式中的method方法..") );
}
public static void show(DemoFuntionalInterface funtionalImpl){
funtionalImpl.method1();
}
}
4,使用Lambda进行性能优化日志案例
Lambda特点:延迟加载,使用前提是存在函数式接口。
当使用Lambda表达式作为参数传递时,仅仅把参数传递到方法中,只有满足一定的条件,才会执行抽象方法中的方法体,所以不会造成性能浪费。
性能浪费例子:
public class Demo1Log {
public static void main(String[] args) {
String msg1 = "Hello";
String msg2 = "World,";
String msg3 = "Java!";
showLog(2,msg1+msg2+msg3);//无论level是何值,都会进行字符串拼接,性能浪费
}
private static void showLog(int level,String msg) {
if(level==1){
System.out.println(msg);
}
}
}
使用lambda表达式进行调优:
@FunctionalInterface
public interface LogInterface {
public abstract String showMessge();
}
public static void showLog(int level,LogInterface logImpl){
//函数式接口作为方法参数
if(level==1){
System.out.println(logImpl.showMessge());
}
}
public class Demo2Log {
public static void main(String[] args) {
String msg1 = "Hello";
String msg2 = "World,";
String msg3 = "Java!";
showLog(1,()->msg1+msg2+msg3);
showLog(2, new LogInterface() {
@Override
public String showMessge() {
System.out.println("有执行");
return msg1+msg2+msg3;
}
});
}
}
函数式接口作为方法返回值:
import java.util.Arrays;
import java.util.Comparator;
public class FuntionalInterfaceReturn {
public static void main(String[] args) {
String[] arr = {"abc","bb","fdfdg","s"};
Arrays.sort(arr,myComparator());
String s = Arrays.toString(arr);
System.out.println(s);
}
public static Comparator<String> myComparator(){
//方法的返回值是一个函数式接口,可以返回一个Lambda表达式
return (o1, o2)->o2.length()-o1.length();
}
}
二,Supplier接口
java.util.function.Supplier接口仅包含一个无参的方法:T get(),用来获取一个泛型参数指定的类型数据。
Supplier接口,即生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据。
import java.util.function.Supplier;
public class DemoSupplier {
public static void main(String[] args) {
// String str = getString(new Supplier<String>() {
// @Override
// public String get() {
// return "胡歌";
// }
// });
String str = getString(() -> "胡歌");
System.out.println(str);
}
public static String getString(Supplier<String> sup){
return sup.get();
}
}
import java.util.function.Supplier;
public class Demo2Supplier {
public static void main(String[] args) {
int[] arr = {12,16,5,0,123,2};
int maxNum = getMax(() -> {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]){
max = arr[i];
}
}
return max;
});
System.out.println(maxNum);
}
public static int getMax(Supplier<Integer> sup){
return sup.get();
}
}
三,Consumer接口
java.util.function.Consumer接口,与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型指定。
Consumer接口中包含抽象方法void accept(T, t),意为消费一个指定泛型的数据。消费方式需自定义(输出、计算等)。
import java.util.function.Consumer;
public class Demo1Consumer {
public static void main(String[] args) {
conSumer("小李子",(String name)->{
String str = new StringBuilder(name).reverse().toString();
System.out.println(str);//子李小
});
}
public static void conSumer(String name, Consumer<String> con){
con.accept(name);
}
}
默认方法:andThen
default Consumer andThen(Consumer<? super T> after),返回一个组合的Consumer ,依次执行此操作,然后执行after操作。
import java.util.function.Consumer;
public class Demo2Consumer {
public static void main(String[] args) {
method("HelloWorld",(t)->{
System.out.println(t.toUpperCase());//HELLOWORLD
},(t)->{
System.out.println(t.toLowerCase());//helloworld
});
}
public static void method(String name, Consumer<String> con1,Consumer<String> con2){
con1.accept(name);
con2.accept(name);
//可使用andThen方法
con1.andThen(con2).accept(name);
}
}
四,Predicate接口
java.util.function.Predicate接口,可对某种数据类型的数据进行判断,结果返回一个布尔值。
Predicate接口中的抽象方法:
boolean test(T t),用来对指定数据类型的数据进行判断的方法。若符合条件。返回true;否则返回false。
Predicate接口中的默认方法:
1,default Predicate and (Predicate<? super T> other),用于连接两个判断条件,方法内部是使用&&连接符连接起来。
方法源码:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
import java.util.function.Predicate;
public class Demo01Predicate {
public static boolean checkString(String str, Predicate<String> pre){
//return pre.test(str);
return pre.negate().test(str);
}
public static boolean checkString2(String str, Predicate<String> pre,Predicate<String> pre2){
//return pre.test(str)&&pre2.test(str);
return pre.and(pre2).test(str);
}
public static void main(String[] args) {
String str = "abcdef";
Boolean res = checkString(str,(s)->s.length()>5);
System.out.println(res);//true
String str2 = "aaabbcd";
Boolean res2 = checkString2(str2,(s)->s.length()>5,(s)->s.contains("f"));
System.out.println(res2);//false
}
}
2,default Predicate or(Predicate<? super T> other)方法,表或者关系。
import java.util.function.Predicate;
public class DemoPredicateOr {
public static boolean checkString(String str, Predicate<String> pre1,Predicate<String> pre2){
return pre1.or(pre2).test(str);
}
public static boolean checkString2(String str,Predicate<String> pre1){
return pre1.negate().test(str);
}
public static void main(String[] args) {
String str = "asdffg";
boolean res = checkString(str, (s1) -> {
return s1.length() > 5;
}, (s1) -> {
return s1.contains("c");
});
System.out.println(res);//true
boolean res2 = checkString2(str, (s) -> {
return s.length()>5;
});
System.out.println(res2);//false
}
}
3,default Predicate negate(Predicate<? super T> other),表取反的意思。
综合案例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Predicate;
public class PredicatePretice {
/*自己写
public static boolean checkString(String str, Predicate<String> pre1,Predicate<String> pre2){
return pre1.and(pre2).test(str);
}
public static void main(String[] args) {
String[] arr = {"迪丽热巴,女","古力娜扎,女","马尔扎哈,男","赵丽颖,女"};
ArrayList<String> list = new ArrayList<>();
for (String p : arr) {
boolean res = checkString(p, (String s1) -> {
return s1.split(",")[0].length()==4;
}, (String s2) -> {
return "女".equals(s2.split(",")[1]);
});
if (res){
list.add(p);
}
}
System.out.println(list);
}
*/
//教程
public static ArrayList<String> filter(String[] arr,Predicate<String> pre1,Predicate<String> pre2){
ArrayList<String> list = new ArrayList<>();
for (String s : arr) {
boolean b = pre1.and(pre2).test(s);
if (b){
list.add(s);
}
}
return list;
}
public static void main(String[] args) {
String[] arr = {"迪丽热巴,女","古力娜扎,女","马尔扎哈,男","赵丽颖,女"};
ArrayList<String> list = filter(arr, s1 -> s1.split(",")[0].length() == 4, s2 -> s2.split(",")[1].equals("女"));
System.out.println(list);
}
}
五,Function<T,R>接口
用来根据一个类型的数据转换得到另一个类型的数据。
主要的抽象方法:
R apply(T, t),根据T获取R类型的结果,如将Integer转为String类型。
默认方法:
andThen,用来进行组合操作,例如将String转为Integer,再将Integer转为String类型。
import java.util.function.Function;
public class Demo01FunctionApply {
public static void change(String str, Function<String,Integer> fun){
Integer in = fun.apply(str);
System.out.println(in);
}
public static void main(String[] args) {
String str = "258";
change(str,s -> Integer.parseInt(s));
}
}
import java.util.function.Function;
public class DemoFunctionandThen {
/*将String转为Integer,加10后再转为String。*/
public static String change(String str, Function<String,Integer> fun1,Function<Integer,String> fun2){
String ss = fun1.andThen(fun2).apply(str);
return ss;
}
public static void main(String[] args) {
String s = "589";
String ss = change(s, (String s1) -> {
return Integer.parseInt(s1);
}, (Integer i) -> {
return ""+i;
});
System.out.println(ss);
}
}
综合案例:
import java.util.function.Function;
public class DemoFunctiongetAge {
/*
public static Integer getAge(String s, Function<String,Integer> fun){
String ageStr = s.split(",")[1];
return fun.apply(ageStr)+10;
}
public static void main(String[] args) {
String s = "赵丽颖,25";
Integer age = getAge(s, s1 -> Integer.parseInt(s1));
System.out.println(age);
}
*/
public static Integer getAge(String s, Function<String,String> fun1,
Function<String,Integer> fun2,
Function<Integer,Integer> fun3){
return fun1.andThen(fun2).andThen(fun3).apply(s);
}
public static void main(String[] args) {
String s = "赵丽颖,26";
int num = getAge(s,(String s1)->{
return s1.split(",")[1];
},(String s2)->{
return Integer.parseInt(s2);
},(Integer num1)->{
return num1+100;
});
System.out.println(num);
}
}