zoukankan      html  css  js  c++  java
  • 面向对象2

    Lambda表达式

    匿名内部类仍然有很多冗余,为了更简洁,JDK8加入了Lambda表达式:

    (参数类型 参数名称) -> { 代码 }

    注意:

    1. Lambda必须具有接口,且接口中只有一个抽象方法
    2. Lambda必须有上下文才能推断,也就是局部变量等

    比如:有个Person类,里面有name和age,做排序:

    import java.util.Arrays;
    
    public class Test {
        public static void main(String[] args) {
            Person[] arr = {
                    new Person("张三", 19),
                    new Person("李四", 18)};
            Arrays.sort(arr, (Person a, Person b) -> {
                return a.getAge() - b.getAge();
            });
            for (Person p : arr) {
                System.out.println(p.getName() + " " + p.getAge());
            }
        }
    }
    

    省略格式:

    1. 小括号内参数可以省略
    2. 如果只有一个参数,括号也可以省略
    3. 如果代码只有一行,花括号/return/分号都可以省略

    函数式接口

    函数式接口:有且仅有一个抽象方法的接口,也就是Lambda使用的接口。

    特点:

    1. 函数前面加一个@FunctionalInterface叫注解,用于检查接口是否是一个函数式接口。
    2. 函数式接口一般作为方法的参数或返回值
    3. 匿名内部类会创建一个.class文件,加载到内存;Lambda表达式不会;

    如,函数式接口

    @FunctionalInterface
    interface MyFunctionInterface {
        public abstract void method();
    }
    

    函数式编程:函数式接口作为方法的参数

    public class Test {
        public static void main(String[] args) {
            startThread(() -> System.out.println("开启线程任务"));
        }
    
        public static void startThread(Runnable run) {
            new Thread(run).start();
        }
    }
    
    

    java.util.function包中提供了大量的函数式接口:

    1. Supplier:传入一个类型的数据 ,返回该类型数据
    2. Consumer:不生产数据,而是消费数据
    3. Predicate:对数据判断,返回一个布尔值
    4. Function:输入一个数据类型,转换成另一个数据类型

    Stream流

    Stream流和IO流不一样,JDK1.8之后,提出Stream流,是为了解决已有集合类库的弊端。

    public class Test {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("张三");
            list.add("李四");
            list.add("张阳");
            list.add("王老五");
            // 两个过滤,一个遍历
            list.stream()
                    .filter(name->name.startsWith("张"))
                    .filter(name->name.length()==2)
                    .forEach(name-> System.out.println(name));
        }
    }
    

    获取流:

    1. JDK8之后,在Collection中加入了default方法stream(),其子类可以直接调用。
    2. Stream接口的静态方法of可以获取数组对应的流。

    流中的方法:

    1. 延迟方法:返回值仍是Stream流,可以链式编程
    2. 终结方法:count()forEach() 。stream流在使用完终结方法,将不能再使用。

    forEach遍历【终结方法】

    Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
    // forEach方法接收一个Consumer接口函数, Consumer.accept()消费一个数据
    stream.forEach((String name) -> System.out.println(name));
    

    filter过滤

    Stream<String> stream = Stream.of("张三", "李四", "张阳", "赵六");
    // filter方法接收一个Predicate接口函数, Predicate.test()返回布尔值
    Stream<String> stream2 =  stream.filter((String name) -> name.startsWith("张"));
    stream2.forEach((String name) -> System.out.println(name));
    

    map类型转换

    Stream<String> stream = Stream.of("1", "2", "3", "4");
    // map方法接收一个Function接口函数, Function.apply()转换数据类型
    Stream<Integer> stream2 =  stream.map((String x) -> Integer.parseInt(x));
    stream2.forEach((Integer x) -> System.out.println(x));
    

    count统计个数【终结方法】

    Stream<String> stream = Stream.of("1", "2", "2", "4");
    System.out.println(stream.count());
    

    limit截取前几个,skip跳过前几个

    Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
    Stream<String> stream2  = stream.limit(3).skip(1);
    stream2.forEach((name) -> System.out.println(name));
    

    concat合并两个流

    Stream<String> stream = Stream.of("张三");
    Stream<String> stream2 = Stream.of("老王");
    Stream<String> stream3  = Stream.concat(stream, stream2);
    stream3.forEach((name) -> System.out.println(name));
    

    方法引用

    Lambda表达式:拿什么参数做什么操作。如果操作方案已经存在,那就没有必要再写一遍 。

    方法引用:用双冒号::表示引用运算符,它所在的表达式表示方法引用。如果Lambda要表达的函数方案存在于某个方法的实现中,那么可以通过双冒号来引用该方法作为Lambda的替代者。

    例如,System.out对象中有一个重载的println(s)方法是我们需要的,那么下面两种写法等效:

    • Lambda表达式:(String s) -> System.out.println(s) ,表示参数通过Lambda传递给println
    • 方法引用:Systeml.out::println ,表示参数直接用println打印

    函数式接口是Lambda的基础,方法引用是Lambda的孪生兄弟。

    通过对象名引用成员方法:

    // Lambda表达式
    printString((s) -> {
    	MethodRerObject obj = new MethodRerObject();
    	obj.printUpperCaseString(s);
    });
            
    // 方法引用:有对象,有对象中的方法,那么直接引用该方法
    MethodRerObject obj2 = new MethodRerObject();
    printString(obj2::printUpperCaseString);
    

    通过类名引用静态成员方法:

    // Math类中有一个abs()静态方法
    method(Math::abs);
    // 自己传递数
    method2(-10, Math::abs);
    

    通过super引用成员方法:

    // 在子类内有一个方法,是调用父类的方法传递给函数式接口
    // Lambda表达式
    method(()->new FuClass().sayHello());
    method(()->super.sayHello());
    // 引用方法
    method(super::sayHello);
    

    通过this引用成员方法:

    // 和用super差不多
    // Lambda表达式
    method(()->this.sayHello());
    // 引用方法
    method(this::sayHello);
    

    类的构造器引用:

    // 有一个类,以及类的函数式接口
    printName("张三", (name) ‐> new Person(name));
    // 方法引用
    printName("张三", Person::new);
    

    数组的构造器引用:

    数组也是Object子类对象,也有构造器,用法和类的构造器一样。

    public class Test {
        public static void main(String[] args) {
            // Lambda表达式
            int[] array = initArray(10, (length) -> new int[length]);
            // 方法引用
            int[] array2 = initArray(10, int[]::new);
        }
    
        public static int[] initArray(int length, ArrayBuilder b) {
            return b.buildArray(length);
        }
    }
    
    // 函数式接口
    @FunctionalInterface
    interface ArrayBuilder {
        int[] buildArray(int length);
    }
    
  • 相关阅读:
    go 字符串转换
    GRU模型结构
    ElasticSearch实战系列八: Filebeat快速入门和使用---图文详解
    H5可视化编辑器(H5 Dooring)
    (转)如何防止Axios对我的请求参数进行编码?
    vue使用element-ui,如何给Label加标签
    vue中$router.push打开新窗口
    (转)webstorm配置svn
    打开gitee.com网站报错
    监控$route无效
  • 原文地址:https://www.cnblogs.com/mingriyingying/p/13581009.html
Copyright © 2011-2022 走看看