函数式接口
有且只有一个抽象方法的接口,称为函数式接口;
在JDK8中新增了 @FunctionalInterface
注解, 可以用其检测接口是否是一个函数式接口;
在JDK8中 java.util.function
包下定义了丰富的函数式接口, 内置四大核心函数式接口:
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型 | T | void | 对类型为T 的对象应用操作,包含方法 void accept(T t) |
Supplier<T> 供给型 | T | 返回类型为T的对象,包含方法 T get() | |
Function<T,R> 函数型 | T | R | 对类型为T的对象应用操作,并返回R 类型的结果对象, 包含方法 R apply(T t) |
Predicate<T> 断定型 | T | Boolean | 确定类型为T 的对象是否满足某约束,并放回Boolean 值,包含方法 boolean test(T t) |
// 自定义函数式接口
@FunctionalInterface
interface MyFunctionInterface<K, V, R> {
// 有且只有一个抽象方法
R check(K t, V e);
static Boolean check2() {
return null;
}
default String check3() {
return null;
}
}
@Test
public void functionTest(){
// 使用匿名实现类方式实例化这些函数式接口
Consumer<String> c = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
c.accept("我是消费型函数式接口");
Supplier<String> s = new Supplier<String>() {
@Override
public String get() {
return "供给型函数式接口匿名实现类";
}
};
System.out.println(s.get());
Function<String, Character[]> f = new Function<String, Character[]>() {
@Override
public Character[] apply(String s) {
char[] chars = s.toCharArray();;
Character[] cs = new Character[chars.length];
for (int i = 0; i<= chars.length-1; i++) {
cs[i] = chars[i];
}
return cs;
}
};
Character[] characters = f.apply("我是函数型函数式接口");
for (Character cr: characters) {
System.out.println(cr);
}
Predicate<String> p = new Predicate<String>() {
@Override
public boolean test(String s) {
Integer i = s.compareTo("");
return Boolean.parseBoolean(i.toString());
}
};
System.out.println(p.test("你是SB"));
}
Lambda表达式
Lambda表达式的本质: 是函数式接口的实例, 使用匿名实现类来实例化接口的方式可以使用Lambda表达式来简化编写过程;
Lambda表达式的公式: (函数式接口抽象方法的形参列表…) -> {函数式接口被重写的抽象方法的方法体}
- -> 左边: lambda形参列表; 本质是接口中的抽象方法的形参列表, 形参列表的参数类型可以省略(类型推断), 如果形参列表有且只有一个参数, 那么一对()可以省略;
- -> : lambda操作符;
- -> 右边: lambda体; 本质是函数式接口中被重写的抽象方法的方法体, lambda体应使用一对{}包裹, 如果lambda体只有一句执行语句(可能是return语句),那么{} 和 return关键字都可以省略;
@Test
public void lambdaTest(){
// 只有一个形参则->左边省略(), 方法体只有一句执行语句则-> 右边省略{}
Consumer<String> c = s -> System.out.println(s);
c.accept("我是消费型函数式接口");
// 没有形参列表 则 -> 左边是(), 方法体只有一个返回语句 则 -> 右边省略{}和return关键字
Supplier<String> s = () -> "供给型函数式接口匿名实现类";
System.out.println(s.get());
// 只有一个形参则->左边省略() 方法体有多条执行语句 则->右边为完整的{方法体...return ....;}
Function<String, Character[]> f = str -> {
char[] chars = str.toCharArray();;
Character[] cs = new Character[chars.length];
for (int i = 0; i<= chars.length-1; i++) {
cs[i] = chars[i];
}
return cs;
};
Character[] characters = f.apply("我是函数型函数式接口");
for (Character cr: characters) {
System.out.println(cr);
}
// 没有形参列表 则 -> 左边是(), 方法体只有一个返回语句 则 -> 右边省略{}和return关键字
Predicate<String> p = str -> Boolean.parseBoolean(((Integer)str.compareTo("")).toString());
System.out.println(p.test("你是SB"));
// 形参列表有多个形参则->左边是(xxx), 方法体只有一个返回语句 则 -> 右边省略{}和return关键字
Comparator<String> comparator = (s1, s2) -> s1.compareTo(s2);
System.out.println(comparator.compare("H", "C"));
// 形参列表有多个形参则->左边是(xxx),方法体有多条执行语句 则->右边为完整的{方法体...return ....;}
// MyFunctionInterface<K,V,R> mfi = (K, V)->{ ... return R};
MyFunctionInterface<String, String[], List<String>> mfi = (check, arr) -> {
List<String> list = new ArrayList<>();
if (arr != null && arr.length > 0) {
for (String str: arr) {
if (str.contains(check)) {
list.add(str);
}
}
}
return list;
};
List<String> list = mfi.check("京", new String[]{"北京","东京","西京","南京","天津"});
System.out.println(list);
}
方法引用与构造器引用
方法引用
方法引用的本质: Lambda表达式的进一步简写, 所以也是函数式接口的实例;
方法引用的公式: 1. 对象::非静态方法; 2. 类::静态方法; 3. 类::非静态方法
使用条件:
- 当存在一个类且这个类的存在一个方法的形参列表以及返回值类型与函数式接口的抽象方法的形参列表以及返回值类型完全相同, 则此类的这个方法可以在函数式接口实例化时使用方法引用的形式被引用;(格式1.2可使用的条件)
- 当存在一个类且此类作为函数式接口的抽象方法的形参列表的第一个参数类型, 同时此类存在一个方法,此方法的形参列表与函数式接口的抽象方法的剩余形参列表相同, 此方法的返回类型与函数式接口的抽象方法返回类型相同,则此类的这个方法可以在函数式接口实例化时使用方法引用的形式被引用;(格式3使用的条件)
个人理解: 其实可以看做某个类的方法在满足上述条件时, 此类的方法可以看做为函数式接口的抽象方法的重写, 所以使用方法引用实例化函数式接口后,函数式接口调用抽象方法时,实际调用的就是被引用的方法;
@Test
public void functionQuoteTest(){
// 类::静态方法 System.out 输出流的 println(String s)方法 与 Consumer 的accept(T t) 方法的参数列表和返回类型一致
Consumer<String> c = System.out::println;
c.accept("哈哈");
// 类::非静态方法 String类本身与Comparator的compare(T o1, T o2)第一个参数类型相同,
// String的compareTo(String anotherStr)方法的形参与Comparator的compare(T o1, T o2)后续的新参相同, 且返回值相同
Comparator<String> comparator = String::compareTo;
System.out.println(comparator.compare("abc", "abd"));
}
构造器引用
Stream API
Stream 是数据渠道, 用于操作数据源(集合,数组等)所生成的元素序列; 集合本质是数据,Stream本质是计算;
Stream 操作的三个步骤: 1.创建: 从数据源中获取; 2.中间操作: 一个中间操作链,对数据源的数据进行计算处理; 3. 终止操作: 也叫终端操作,一点执行终止操作, 就执行中间操作链, 并产生新的结果.不会对原来的数据产生影响; Stream执行终止操作后不可以继续使用;
class BasketBallPlayer {
private String name;
private Integer age;
private BigDecimal salary;
public BasketBallPlayer(String name, Integer age, BigDecimal salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public BasketBallPlayer(BigDecimal salary) {
this.salary = salary;
}
public BasketBallPlayer(String name) {
this.name = name;
}
public BasketBallPlayer() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
@Override
public String toString() {
return "BasketBallPlayer{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BasketBallPlayer that = (BasketBallPlayer) o;
return Objects.equals(name, that.name) &&
Objects.equals(age, that.age) &&
Objects.equals(salary, that.salary);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
}
Stream实例化方式
public static List<BasketBallPlayer> getBasketBallPlayers(){
List<BasketBallPlayer> list = new ArrayList<>();
list.add(new BasketBallPlayer("Kobe Bryant",40,new BigDecimal("40000000")));
list.add(new BasketBallPlayer("LeBron James",36,new BigDecimal("30000000")));
list.add(new BasketBallPlayer("Michael Jordan",50,new BigDecimal("60000000")));
list.add(new BasketBallPlayer("Stephen Curry",33,new BigDecimal("10000000")));
list.add(new BasketBallPlayer("Kevin Durant",29,new BigDecimal("25000000")));
list.add(new BasketBallPlayer("Dwyane Wade",41,new BigDecimal("15000000")));
list.add(new BasketBallPlayer("Dwyane Wade",41,new BigDecimal("15000000")));
return list;
}
@Test
public void streamTest(){
// 实例化
// 通过集合获取
List<BasketBallPlayer> basketBallPlayers = getBasketBallPlayers();
Stream<BasketBallPlayer> basketBallPlayerStream = basketBallPlayers.stream();
// 通过Arrays获取
String[] strings = {"AA", "BB", "CC", "DD"};
Stream<String> stringStream = Arrays.stream(strings);
// Stream.of(T t...)获取
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
// Stream.iterate(final T seed, final UnaryOperator<T> f)获取
Stream<Integer> iterate = Stream.iterate(0, t -> t + 2).limit(10);
}
中间操作
@Test
public void streamTest(){
List<BasketBallPlayer> basketBallPlayers = getBasketBallPlayers();
// 中间操作
System.out.println("filter********************");
// Stream<T> filter(Predicate<? super T> predicate);
// 传入Predicate判定型函数式接口, 用于过滤流中不符合条件的元素
Stream<BasketBallPlayer> filter = basketBallPlayers.stream().filter(e -> e.getAge() > 30); // 获取年龄大于三十的球员
filter.forEach(System.out::println); // 执行终止操作
System.out.println("limit********************");
// limit(long maxSize); 截断流中前几个元素, 只保留0-maxSize元素
Stream<BasketBallPlayer> limit = basketBallPlayers.stream().limit(3);
limit.forEach(System.out::println); // 执行终止操作
System.out.println("skip********************");
// skip(long n); 截断流中后几个元素 只保留 n至流的最后一个元素, 如果n大于流的元素格式,则返回空的流
Stream<BasketBallPlayer> skip = basketBallPlayers.stream().skip(3);
skip.forEach(System.out::println); // 执行终止操作
System.out.println("distinct********************");
// distinct() 去重 通过元素的equals()和hashCode()方法比较
Stream<BasketBallPlayer> distinct = basketBallPlayers.stream().distinct();
distinct.forEach(System.out::println); // 执行终止操作
// 映射
System.out.println("map********************");
// map(Function<? super T, ? extends R> mapper)
Stream<String> map = basketBallPlayers.stream().map(BasketBallPlayer::getName);
map.forEach(System.out::println);
// flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
// basketBallPlayers.stream().flatMap()
// 排序
System.out.println("sorted********************");
// sorted() 调用空参接口需要T实现Comparator接口才行
// sorted(Comparator<? super T> comparator)
Stream<BasketBallPlayer> sorted = basketBallPlayers.stream().sorted((b1, b2) -> b1.getSalary().compareTo(b2.getSalary()));
sorted.forEach(System.out::println);
}
@Test
public void streamTest(){
// 终止操作
// 匹配 查找
System.out.println("allMatch********************");
// boolean allMatch(Predicate<? super T> predicate); 传入断定型函数式接口实例,表示是否所有数据都满足条件
boolean allMatch = basketBallPlayers.stream().allMatch(e -> e.getAge() > 30);
System.out.println(allMatch);
System.out.println("anyMatch********************");
// boolean anyMatch(Predicate<? super T> predicate); 传入断定型函数式接口实例,表示是否存在某个数据满足条件
boolean anyMatch = basketBallPlayers.stream().anyMatch(e -> e.getAge() > 30);
System.out.println(anyMatch);
System.out.println("noneMatch********************");
// boolean noneMatch(Predicate<? super T> predicate); 传入断定型函数式接口实例,表示是否所有数据都不满足条件
boolean noneMatch = basketBallPlayers.stream().noneMatch(e -> e.getAge() > 60);
System.out.println(noneMatch);
System.out.println("findFirst********************");
// Optional<T> findFirst(); 返回流中的第一个元素 使用Optional包装
Optional<BasketBallPlayer> first = basketBallPlayers.stream().findFirst();
System.out.println(first);
System.out.println("findAny********************");
// 随机返回一个
Optional<BasketBallPlayer> any = basketBallPlayers.stream().findAny();
System.out.println(any);
System.out.println("count********************");
// 查找个数
long count = basketBallPlayers.stream().count();
System.out.println(count);
System.out.println("max********************");
// Optional<T> max(Comparator<? super T> comparator); 最大值
Optional<BasketBallPlayer> max = basketBallPlayers.stream().max((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
System.out.println(max);
System.out.println("min********************");
// 最小值
Optional<BasketBallPlayer> min = basketBallPlayers.stream().min((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
System.out.println(min);
System.out.println("forEach********************");
// 遍历
basketBallPlayers.stream().forEach(System.out::println);
// 归约
System.out.println("reduce********************");
// 将流中元素反复结合, 得到一个值 返回Optional<T>
Optional<BigDecimal> reduce = basketBallPlayers.stream().map(BasketBallPlayer::getSalary).reduce(BigDecimal::add);
System.out.println(reduce);
// 将流中元素反复结合, 得到一个值 返回T
BigDecimal reduce1 = basketBallPlayers.stream().map(BasketBallPlayer::getSalary).reduce(new BigDecimal("0"), BigDecimal::add);
System.out.println(reduce1);
// 收集
List<BasketBallPlayer> collect = basketBallPlayers.stream().sorted((e1, e2) -> e1.getSalary().compareTo(e2.getSalary())).collect(Collectors.toList());
}
Optional
java.util.Optional 是一个容器类, 他可以保存类型T的值, 代表这个值存在, 或者仅仅保存NULL, 标志这个值不存在. 远啦用NULL表示一个至不存在, 现在用Optional可以更好的表达这个概念,并且可以避免空指针异常;