目录
一.函数式接口Functional Interface
只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface
接口定义,强化语义规范。
函数式接口,也被称为SAM
接口(Single Abstract Method Interfaces
):
基于函数式接口,可以使用Lambda
表达式进行实现,实现函数式编程。
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}// lambda表达式实现字符串数组排序
Arrays.sort(array, (x1,x2) -> {
if (x1.length() != x2.length()) {
return x1.length() - x2.length();
} else {
return x1.compareTo(x2);
}
} );2:迭代
List<String> langList = Arrays.asList("Basic","QBasic","c","c++","PowerBuilder","Visual Basic");
langList.forEach((name)->{
System.out.println(name);
});
内置函数式接口来由来
我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口
求数组的的所有元素和---自定义一个内置函数接口:
package com.itheima.demo03functionalinterface;
import java.util.List;
public class Demo01UserFunctionalInterface {
public static void main(String[] args) {
// 调用函数式接口中的方法
method((arr) -> {
int sum = 0;
for (int n : arr) {
sum += n;
}
return sum;
});
}
// 使用自定义的函数式接口作为方法参数
public static void method(Operator op) {
int[] arr = {1, 2, 3, 4};
int sum = op.getSum(arr);
System.out.println("sum = " + sum);
}
}
@FunctionalInterface
interface Operator {
public abstract int getSum(int[] arr);
}
1. Supplier接口 --供给型接口
ava.util.function.Supplier<T> 接口 - 方法没有参数,有返回值--供给型接口。
它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口。
@FunctionalInterface
public interface Supplier<T> {
public abstract T get();
}
使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。提示:接口的泛型请使用 java.lang.Integer 类。注意代码的执行顺序
public class Demo02 {
public static void main(String[] args) {
System.out.println("进入到main方法");
//使用lambda表达式表示
Supplier<Integer> s1 = () -> {System.out.println("get方法开始");
int[] arr = {4,23,3,2,12,9303};
int index = new Random().nextInt(arr.length);
System.out.println("get方法结束");
return arr[index];};
printNumber(s1);
System.out.println("main方法结束");
}private static void printNumber(Supplier<Integer> sup) {
System.out.println("随机值为为:");
System.out.println(sup.get());
System.out.println("print结束");
}}
2. Consumer接口 --消费型接口
java.util.function.Consumer<T> 接口则正好相反 --方法有参数,没有返回值,它不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定。 --消费型接口
Consumer消费型接口,可以拿到accept方法参数传递过来的数据进行处理, 有参无返回的接口。
@FunctionalInterface
public interface Consumer<T> {
public abstract void accept(T t);
}
public class Demo03 {
// 使用Lambda表达式将一个字符串转成大写的字符串
public static void main(String[] args) {
System.out.println("开始啦");
printHello((String str) -> {
System.out.println(str.toUpperCase());
});
}public static void printHello(Consumer<String> consumer) {
System.out.println("aaa");
consumer.accept("Hello World");
}
}
代码练习2:默认方法:andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费一个数据的时候,首先做一个操 作,然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。下面是JDK的源代码:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };//箭头后的为返回Consumer对象中重写的方法体
}
//此时需要注意,我们返回的是一个Lambda表达式,就相当于返回了一个被重写了抽象方法的Consumer<T>类对象
// 即该类对象中,重写了accept()抽象方法,方法体为{ s -> System.out.println(s); s -> System.out.println(new StringBuilder(s).reverse().toString();}
// 即con1.andThen(con2).accept(name);,就变为 Consumer<T>.accept(name);
// Consumer<T>调用本身的accept()方法,并传入字符串参数 “林青霞 ”,所以会输出林青霞,霞青林
// 返回的是一个Consumer类型的对象,而不是直接去对此对象及性能调用
备注: java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出
NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
要想实现组合,需要两个或多个Lambda表达式即可,而 andThen 的语义正是“一步接一步”操作。例如两个步骤组合的情况
3.Function接口 --转换型接口
java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。有参数有返回值。----- 此方法接收一个参数,加工处理成另一种,称为转换型接口
Function转换型接口,对apply方法传入的T类型数据进行处理,返回R类型的结果,有参有返回的接口。使用的场景 例如:将 String类型转换为 Integer类型。
@FunctionalInterface
public interface Function<T, R> {
public abstract R apply(T t);
}
public static void main(String[] args) {
// 通过lambda表达式方式创建一个Function类型的对象// 测试1: 返回字符串的长度
// Function<String, Integer> f = (String str) -> {
// return str.length();
// };
// 省略写法
Function<String, Integer> f = str -> str.length();
method(f,"abcdef");// 测试2:截取字符串的前五个字符。转成数字,要求传入的参数类型为数字字符串类型
Function<String, Integer> f1 = str -> Integer.parseInt(str.substring(0, 2));
method(f1, "121273asheji");}
/*
* 函数式接口把一个String转换成数字类型
*/
public static void method(Function<String, Integer> f, String str) {
Integer result = f.apply(str);
System.out.println(result);
}
默认方法: andThen:该方法同样用于“先做什么,再做什么”的场景,和 Consumer 中的 andThen差不多:
function中有一个默认方法,对应的代码的源码为如下
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
4. Predicate接口--断言型接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用
java.util.function.Predicate<T> 接口。------接收一个参数,返回一个boolean类型的值,称为判断型接口
@FunctionalInterface
public interface Predicate<T> {
public abstract boolean test(T t);
}
Predicate接口用于做判断,返回boolean类型的值
判断某个数字是否是偶数,判断某个数字是否大于0
public class Demo07Predicate {
public static void main(String[] args) {// 通过lambda的方式创建Predicate类型的对象,需要重写test方法
//判断是否是偶数
Predicate<Integer> p1 = (Integer num) -> {
System.out.println("是否是偶数");
return (num & 1) == 0;
};
method(p1, 29);
//判断是否>100
Predicate<Integer> p2 = (Integer num) -> {
System.out.println("是否>100");
return num >100;
};
method(p2, 100);
}/*
* 函数式接口作为方法的参数 判断一个数字
*/
public static void method(Predicate<Integer> p, Integer num) {
boolean b = p.test(num);
System.out.println(b);
}
}
默认方法: and or
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate条件使用“与”逻辑连接起来实 现“并且”的效果时,可以使用default方法 and 。其JDK源码为:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}//与 and 的“与”类似,默认方法 or实现逻辑关系中的“或”。JDK源码为:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
5. Comparator接口--比较器接口
比较器接口,用于比较指定元素值的大小。Java
8版本中,添加了多个新的default
方法,用于比较器合并、反转等操作。
// 案例数据
List<String> langList = Arrays.asList("Basic", "QBasic","HTML", "c", "c++", "PowerBuilder", "go", "Visual Basic", "c#","java");// 按照ASCII码比较
Comparator<String> comparator1 = (s1, s2) -> {
return s1.compareTo(s2);
};// 按照长度比较
Comparator<String> comparator2 = (s1, s2) -> {
return s1.length() - s2.length();
};// 先比较长度,再比较ASCII码
Comparator<String> comparator3 = comparator2.thenComparing(comparator1);// 在comparator3的基础上,反转条件
Comparator<String> comparator4 = comparator2.reversed();// 按照指定Comparator,进行排序
langList.sort(comparator2);