JDK8 特性(函数式接口、Stream流、方法引用)

函数式接口

常用函数式接口:Supplier Consumer Predicate Function

Supplier(生产者)

1、T get( ) - 得到一个对象

public class Demo {
    // 为了使用Lambda表达式, 所以将Supplier作为方法参数使用
    public static String getInstance(Supplier<String> sup) {
        // 调用Supplier 的get方法
        return sup.get();
    }
    public static void main(String[] args) {
        // 调用getInstance方法, 需要传递一个Supplier接口实现类
        // 又因为Supplier接口是函数式接口, 所以可以使用Lambda表达式
        String str = getInstance(() -> {
            // 这是生产字符串的过程
            return "hello";});
        System.out.println(str);
    }
}

Consumer(消费者)
1、void accept(T t) - 使用这个对象

public class Demo {
    /*
        为了使用Lambda表达式, 需要将Consumer接口作为方法参数
        因为Consumer接口的accept方法需要一个对象来消费, 所以再多传入一个String参数
     */
    public static void toUpper(String str, Consumer<String> consumer) {
        consumer.accept(str);
    }

    public static void main(String[] args) {
        toUpper("hello", s -> {
            // 在这里写消费/使用这个s对象的代码
            // 消费方式: 将 s 进行反转
            String str = new StringBuilder(s).reverse().toString();
            System.out.println(str);
        });
    }
}

2、默认方法:andThen(Consumer) - 将两个消费方式组合在一块

public class Demo {
    /**
     * 因为要使用andThen方法, 所以需要两个Consumer对象
     * 并且accept方法需要消费一个对象, 所以还需要一个String对象
     */
    public static void methodAndThen(String str, Consumer<String> con1, Consumer<String> con2) {
        /*con1.accept(str);
        con2.accept(str);*/
        con1.andThen(con2).accept(str);
    }
    public static void main(String[] args) {
        methodAndThen("JavaGood",
                // 第一次消费, 将字符串全部变大写, 并且打印
                s -> {
                    System.out.println(s.toUpperCase());
                },
                // 第2次消费, 将字符串全部变小写, 并且打印
                s -> {
                    System.out.println(s.toLowerCase());
                });
    }
}

Predicate
1、boolean test(T t) - 对对象做判断

public class Demo {
    public static void method01(String str, Predicate<String> pre) {
        boolean b = pre.test(str);
        System.out.println(b);
    }
    public static void main(String[] args) {
        method01("www", (s) -> {
            return s.length() == 2;
        });
    }
}

2、默认方法:or(||) - and(&&) - negate(!)

public class DemoAnd {
    public static void strPredicate(String str, Predicate<String> pre1, Predicate<String> pre2) {
        /*boolean b1 = pre1.test(str);
        boolean b2 = pre2.test(str);
        System.out.println(b1 && b2);*/

        boolean b = pre1.and(pre2).test(str);
        System.out.println(b);
    }
    public static void main(String[] args) {
        strPredicate("Hello Tony!",
                s -> s.length() > 10,
                s -> s.startsWith("H"));
    }
}
public class DemoOr {
    public static void strPredicate(String str, Predicate<String> pre1, Predicate<String> pre2) {
        // boolean b = pre1.test(str) || pre2.test(str);

        boolean b1 = pre1.or(pre2).test(str);
        System.out.println(b1);
    }
    public static void main(String[] args) {
        strPredicate("Hello Tony!",
                s -> s.split(" ").length > 10,
                s -> s.startsWith("H"));
    }
}
public class DemoNegate {
    public static void m1(String str, Predicate<String> pre) {
        /*boolean b = pre.test(str);
        System.out.println(!b);*/

        boolean b1 = pre.negate().test(str);
        System.out.println(b1);
    }
    public static void main(String[] args) {
        m1("hello Tony !",
                s -> s.split(" ")[1].length() > 3);
    }
}

例:

public class DemoTest {
    public static boolean filterName(String str, Predicate<String> p1, Predicate<String> p2) {
        boolean b = p1.and(p2).test(str);
        return b;
    }
    public static void main(String[] args) {
        String[] array = {"abcd,女", "ww,女", "bcde,男", "cdef,女"};
        ArrayList<String> list = new ArrayList<>();
        for (String str : array) {
            boolean b = filterName(str,
                    // 1.必须为女生;
                    s -> s.split(",")[1].equals("女"),
                    // 2.姓名为4个字。
                    s -> s.split(",")[0].length() == 4
            );
            if (b) {
                list.add(str);
            }
        }
        System.out.println(list);
    }
}

Function<T, R>
1、R apply(T t) - 类型转换

public class Demo {
    // String -> Integer
    public static void change(String str, Function<String, Integer> fun) {
        int i = fun.apply(str);
        System.out.println(i);
    }
    public static void main(String[] args) {
        change("123", s -> Integer.valueOf(s));
    }
}

2、默认方法:andThen(Function) - 连续做两种类型转换

public class DemoAndThen {
    // 将 "123" -> 转换成 int 后 +10
    //      String->Integer  Function<String, Integer>
    // 将 加完后的 int 值, 转换成 String, 2进制的格式
    //      Integer->String  Function<Integer, String>
    public static void change(String str, Function<String, Integer> fun1, Function<Integer, String> fun2) {
        /*Integer i = fun1.apply(str);
        i += 10;

        String string = fun2.apply(i);
        System.out.println(string);*/
        String result = fun1.andThen(fun2).apply(str);
        System.out.println(result);
    }
    public static void main(String[] args) {
        change("123",
                s -> Integer.valueOf(s) + 10,
                i -> Integer.toBinaryString(i));
    }
}

例:

/**
 * String str = "ww, 20";
 * 1. 将字符串截取数字年龄部分,得到字符串;
 *      "ww, 20" -> "20"   Function<String, String>
 * 2. 将上一步的字符串转换成为int类型的数字;
 *      "20" -> 20     Function<String, Integer>
 * 3. 将上一步的int数字累加100,得到结果int数字。
 *      20 -> 120      Function<Integer, Integer>
 */
public class DemoTest {
    public static void change(String str, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
        int i = fun1.andThen(fun2).andThen(fun3).apply(str);
        System.out.println(i);
    }
    public static void main(String[] args) {
        change("ww, 20",
               // "ww, 20" -> "20"
               s -> s.split("[, ]+")[1],
               // "20" -> 20
               s -> Integer.valueOf(s),
               // 20 -> 120
               i -> i + 100 );
    }
}

Stream流

数组或者集合进行操作

1、获取流

        // 1.单列集合获得流对象 List Set
        // List -> Stream
        List<String> list = List.of("aa", "bb","cc","dd");
        Stream<String> streamList = list.stream();
        // Set -> Stream
        Set<String> set = Set.of("aa", "bb", "cc", "dd");
        Stream<String> streamSet = set.stream();

        // 2.多列集合 Map
        Map<Integer, String> map = Map.of(1, "aa", 2, "bb", 3, "cc", 4, "dd");
        // 获得map中的key
        Set<Integer> keys = map.keySet();
        Stream<Integer> streamKey = keys.stream();
        // 获得map中 key-value对 entry
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        Stream<Map.Entry<Integer, String>> streamEntry = entries.stream();
        // 获得value部分
        Collection<String> values = map.values();
        Stream<String> streamValues = values.stream();

        // 3.数组获得Stream流的方式
        Integer[] arrInt = {1,2,3,4,5};
        Stream<Integer> streamInt = Stream.of(arrInt);
        // 4.传入数组的方式可以使用可变长参数替代
        Stream<Integer> streamInt2 = Stream.of(1, 2, 3, 4, 5);

2、常用API
1.void forEach(Consumer) - 终结方法 (消费)
2. Stream filter(Predicate) - 延迟方法(判断)
3. Stream map(Function<T, R>) - 延迟方法(类型转换)
4.static Stream concat(Stream, Stream) -延迟方法(将两个流拼接成一个)

public class Demo {
    public static void main(String[] args) {
        // 第一支队伍
        ArrayList<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("⽯破天");
        one.add("⽯中⽟");
        one.add("⽼⼦");
        one.add("庄⼦");
        one.add("洪七公");
        // 第二支队伍
        ArrayList<String> two = new ArrayList<>();
        two.add("古⼒娜扎");
        two.add("张⽆忌");
        two.add("赵丽颖");
        two.add("张三丰");
        two.add("尼古拉斯赵四");
        two.add("张天爱");
        two.add("张⼆狗");
        // 1. 第一个队伍只要名字为3个字的成员姓名;存储到⼀个新集合中。
        Stream<String> oneStream = one.stream();
        Stream<String> oneStream2 = oneStream.filter(name -> name.length() == 3);
        // 2. 第一个队伍筛选之后只要前3个⼈;存储到⼀个新集合中。
        Stream<String> oneStream3 = oneStream2.limit(3);
        // 3. 第二个队伍只要姓张的成员姓名;存储到⼀个新集合中。
        Stream<String> twoStream = two.stream().filter(name -> name.startsWith("张"));
        // 4. 第二个队伍筛选之后不要前2个⼈;存储到⼀个新集合中。
        Stream<String> twoStream2 = twoStream.skip(2);
        // 5. 将两个队伍合并为⼀个队伍;存储到⼀个新集合中。
        Stream<String> stream = Stream.concat(oneStream3, twoStream2);
        // 6. 根据姓名创建 Person 对象;存储到⼀个新集合中。
        Stream<Person> personStream = stream.map(s -> new Person(s));
        // 7. 打印整个队伍的Person对象信息。
        personStream.forEach(p -> System.out.println(p));
    }
}

方法引用

Lambda 的简化:(对象、类、this、super、数组)

1.方法引用是对Lambda的优化, 换句话说是在Lambda内部调用了方法
2.Lambda内部调用的方法使用的参数, 就是Lambda传递进来的参数
3.方法引用也遵循了之前学习的面向对象的理论知识

@FunctionalInterface
public interface Printable {
    void print(String s);
}

public class Demo {
    public static void print(String s, Printable p) {
        p.print(s);
    }
    public static void main(String[] args) {
        /**
         * s -> System.out.println(s)
         * 1.参数s 直接传给了 println 方法使用
         * 2.System.out 对象本身就是存在的
         * 3.println() 这个方法本身也是存在的
         * 4.println方法的参数就是 接口方法的参数
         * -- 就可以简化
         */
        /*print("Hello Lambda",
                s -> {System.out.println(s);});*/
        // 使用 方法引用 来简化Lambda
        print("Hello Lambda", System.out::println);
    }
}

通过对象名引用成员方法

@FunctionalInterface
public interface Printable {
    void print(String s);
}

public class MyObjectMethod {
    public void printUpperCase(String s) {
        System.out.println(s.toUpperCase());
    }
}

public class Demo {
    public static void method1(String s, Printable p) {
        p.print(s);
    }
    public static void main(String[] args) {
       /* method1("hello", s -> {
            // 1.先创建MyObjectMethod对象
            MyObjectMethod obj = new MyObjectMethod();
            // 2.调用 printUpperCase 这个方法
            obj.printUpperCase(s);
        });*/

        // 使用方法引用来优化
        /*
            1.对象已经存在 obj
            2.方法已经存在 printUpperCase
         */
        MyObjectMethod obj = new MyObjectMethod();
        method1("hello", obj::printUpperCase);
    }
}

通过类名称引用静态方法

@FunctionalInterface
public interface Calcable {
    int calAbs(int n);
}

public class Demo {
    public static int cal(int n, Calcable c) {
        return c.calAbs(n);
    }
    public static void main(String[] args) {
        /*int t = cal(-10, n->{return Math.abs(n);});
        System.out.println(t);*/
        /**
         * 1.方法 已经存在 abs
         * 2.类存在 Math
         */
        // 使用方法引用来优化
        int t = cal(-10, Math::abs);
        System.out.println(t);
    }
}

通过super引用成员方法

public interface Greetable {
    void greet(String message);
}

public class Human {
    public void hi(String message) {
        System.out.println("hi Human!" + message);
    }
}

public class Man extends Human {
    // 重写的父类的hi方法
    public void hi(String message) {
        System.out.println("Hi Man!" + message);
    }
    // 定义一个sayHello, 目的是为了传入Lambda表达式
    public void sayHello(String s, Greetable g) {
        g.greet(s);
    }
    // 这个方法的目的, 是为了调用 sayHello
    public void show() {
       /* sayHello("吃了吗", s->{
            // 调用父类的hi方法
            super.hi(s);
        });*/
        /**
         * 1.super对象已存在
         * 2.方法hi已存在
         */
        sayHello("吃了吗", super::hi);
    }

    public static void main(String[] args) {
        new Man().show();
    }
}

通过this引用成员方法

public interface Richable {
    void buy(String str);
}

public class Husband {
    public void buyHouse(String str) {
        System.out.println("在" + str + "买了一套三居室");
    }
    public void marry(String str, Richable ric) {
        ric.buy(str);
    }
    public void show() {
        /*marry("北京三环内", s->{
            this.buyHouse(s);
        });*/
        /**
         * this 已经存在
         * buyHouse 已经存在
         */
        // 方法引用优化
        marry("北京三环内", this::buyHouse);
    }
    public static void main(String[] args) {
        new Husband().show();
    }
}

类的构造器引用

public interface PersonBuilder {
    // 通过传入的name参数 构造一个Person对象并返回
//    Person builderPerson(String name);
    Person builderPerson();
}

public class Person {
    private String name;
    public Person() {
        System.out.println("无参构造方法");
    }
    public Person(String name) {
        this.name = name;
        System.out.println("有参构造方法");
    }
    public String getName() {
        return name;
    }
}

public class Demo {
    public static void build(String name, PersonBuilder builder) {
        /*Person person = builder.builderPerson(name);
        System.out.println(person.getName());*/
        Person person = builder.builderPerson();
        System.out.println(person.getName());
    }
    public static void main(String[] args) {
//        build("ww",
//                name -> new Person(name));
        // 有参构造
        // 构造器本身是存在的
        build("ww", Person::new);
        // 无参构造
        /*build("ww",
                () -> new Person());*/
    }
}

数组的构造器引用

public interface ArrayBuilder {
    // 根据n - 数组长度, 来创建一个新的数组
    int[] builderArray(int n);
}

public class Demo {
    public static int[] builder(int n, ArrayBuilder arrBuild) {
        return arrBuild.builderArray(n);
    }
    public static void main(String[] args) {
//        int[] array = builder(10, n -> new int[n]);
        int[] array = builder(10, int[]::new);
        System.out.println(array.length);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值