java之父-新特性

发布于:2025-08-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

一.函数式接口Functional Interface

1. Supplier接口 --供给型接口

2. Consumer接口 --消费型接口

3.Function接口 --转换型接口

4. Predicate接口--断言型接口

5. Comparator接口--比较器接口


一.函数式接口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接口--比较器接口

比较器接口,用于比较指定元素值的大小。Java8版本中,添加了多个新的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);


网站公告

今日签到

点亮在社区的每一天
去签到