面向对象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);
}
原文地址:https://www.cnblogs.com/mingriyingying/p/13581009.html