java11的新特性

java 11的新特性主要体现在:

函数式接口、Lambda表达式、方法引用/构造器引用、StreamAPI、接口的增强

1、Lambda表达式

Lambda表达式是一个匿名函数,我们可以把lambda表达式理解为是一段可以传递的代码。使用lambda表达式 可以写出更简洁 更灵活的代码。

1.1 Lambda 表达式的语法

(s1,s2) -> s1.compareTo(s2)


语法中:

    -> 称为lambda操作符或箭头操作符

    左边 指定了lambda表达式的参数列表

    右边 指定lambda体。是抽象方法的实现逻辑 。也是lambda表达式的实现的功能

语法一: 无参无返回值

Runnable r2 = ()-> System.out.println("hello world-----");

语法二:有一个参数 但是没有返回值

    @Test
    public void lambdaTest3(){
        Consumer<String> c = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        // lambda表达式的写法   由泛型推断出参数的类型--称为类型推断
        Consumer<String> c1 = s->System.out.println(s);
        c.accept("aaaaaaaa");
    }

语法三:有多个参数 多条执行语句 并且可以有返回值

 @Test
    public void lambdaTest4(){
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println("比较两个整数的大小");
                int res = o1.compareTo(o2);
                return res;
            }
        };
        //lambda表达式  当有多条语句时  大括号不能省略
        Comparator<Integer> comp = (o1, o2)->{
            System.out.println("比较两个整数的大小");
            int res = o1.compareTo(o2);
            return res;
        };
    }

语法四:有多个参数 只有一条返回语句

 //lambda表达式   有多个参数,只有一条返回语句  此时大括号可以省略  return 也可以省略
        Comparator<Integer> comp = (o1, o2)-> o1.compareTo(o2);
        System.out.println(comp.compare(10,20));

lambda表达式和匿名内部类的区别

    所需的类型不同 :
        匿名内部类中。可以是接口 也可以是抽象类 还可以是具体的类
        lambda表达式 只能是接口

    使用的限制不同:
        如果接口中仅有一个抽象方法 可以使用lambda表达式 也可以是用匿名内部类
        如果接口中有多个抽象方法 只能使用匿名内部类 不能使用lambda表达式

    实现的原理不同:
        匿名内部类编译之后 产生一个单独的字节码文件
        lambda表达式 编译之后 没有单独的字节码class文件 对应的字节码在运行时产生。

2、函数式接口

2.1 什么是函数式接口
只包含一个抽象方法的接口 称为函数式接口

@FunctionalInterface 可以用来检测接口是否是函数式接口。

java.util .function包下定义了大量的函数式接口

因为在java中,lambda表达式是一个对象,而不是函数,他们必须依附于一类特别的对象类型—函数式接口

在java中,lambda表达式就是一个函数式接口的实现

2.2 自定义函数式接口

@FunctionalInterface
public interface InterFunction {
    int  getValue();//函数式接口只能有一个抽象方法
}

函数式接口中使用泛型

@FunctionalInterface
public interface InterFunction<T> {
    T  getValue(T t);
}

    @Test
    public void lambdaTest5(){
        InterFunction<String> fun = s-> s.toUpperCase();
        System.out.println(fun.getValue("abc"));
    }

2.3 作为参数传递Lambda表达式

   public String toUpperCaseString(InterFunction<String> fun,String str){
        return  fun.getValue(str);
    }
    @Test
    public void lambdaTest6(){
         String newString = toUpperCaseString(s-> s.toUpperCase(),"abcdef");
        System.out.println(newString);
    }

2.4 JAVA 内置的四大核心函数式接口

Interface Consumer<T>  
void accept(T t)   对类型T的对象应用操作。 

Interface Supplier<T>
T get()  返回类型为T的对象

Interface Function<T,R>
R apply(T t)   将类型为T的对象进行相应的操作处理  之后返回一个R类型的对象

Interface Predicate<T>  
boolean test(T t)  确定类型为T的对象是否满足要求 

3、接口的组成更新

3.1 ## 7.1 接口组成更新

​ 常量 public static final

​ 抽象方法 public abstract

jdk8引入

​ 默认方法 public default

​ 静态方法

​ 私有方法

3.2 默认方法

格式:
public default 返回值类型 方法名(){

}

  default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }

注意事项:

    默认方法不能是抽象方法 所以他不强制重写,但是也可以重写 重写的时候需要去掉default修饰符

    public可以省略 但是default不能省略

3.3 静态方法

public static 返回值类型  方法名(){

}

注意事项:

    静态方法只能通过接口名调用, 不能通过实现类或者对象名调用
    public可以省略 static 不能省略

3.4 私有方法

private 返回值类型  方法名(){
}

注意事项:

    默认方法可以调用私有的静态方法和非静态方法
    静态方法只能调用私有的静态方法

4、方法引用
4.1 :: 方法引用符

​ 改符号引用运算符 而他所在的表达式称为方法引用

4.2 引用类方法

类名 :: 静态方法名

static int    parseInt(String s) 将字符串参数解析为带符号的十进制整数。

@FunctionalInterface
public interface Converter {
    int converter(String s);
}


public class ConverterDemo {
    public static void main(String[] args) {
        // lambda
        userConverter(s->Integer.parseInt(s),"123");
        //方法引用
        userConverter(Integer :: parseInt,"456");
    }
    public static  void userConverter(Converter c,String s){
       int i =   c.converter(s);
        System.out.println(i);
    }
}
4.3 对象的实例方法的引用

对象::成员方法

@FunctionalInterface
public interface Printer {
    void printUpCase(String str);
}

public class PrintString {
    public void printUpper(String s){
      String res =   s.toUpperCase();
      System.out.println(res);
    }
}

public class PrinterDemo {
    public static void main(String[] args) {
        userPrinter(str -> System.out.println(str.toUpperCase()),"hello");
        PrintString ps = new PrintString();
        userPrinter(ps::printUpper,"world");
    }
    public static  void userPrinter(Printer p ,String s){
         p.printUpCase(s);
    }
}
4.4 构造引用
格式:

类名 :: new

@FunctionalInterface
public interface StudentInterface {
    Student build(String name,int age);
}
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class StudentDemo {
    public static void main(String[] args) {
        //lambda表达式
        userStudent((name,age)->new Student(name,age));
        //构造引用
        userStudent(Student::new);
    }
    public static void userStudent(StudentInterface si){
      Student stu = si.build("张三",21);
        System.out.println(stu.getName() +"---"+stu.getAge());
    }
}

5、StreamAPI
5.1 Stream 流

    java. util.stream. Stream是Java.8新加入的最常用的流接口。(这并不是一 一个函数式接口。)

    Stream带来的好处:
    直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤流、打印

5.2 常见的方法

1、 获取流(生成流)
通过数据源(集合,数组)生成流 list.stream

    获取一个流非常简单,有以下几种常用的方式:
        所有的Collection集合都可以通过stream默认方法获取流;

default Stream<E> stream ()

    stream接口的静态方法of可以获取数组对应的流。

static <T> Stream<T> of (T... values )
参数是一个可变参数。那么我们就可以传递一个数组

2、 中间操作

​ 一个流的后面可以跟随零个或多个中间操作,目的只要是打开流,对其中数据进行过滤/映射,然后返回一个新的流。交给下一个操作使用

    Stream流中的常用方法**_ forEach**

void forEach(Consumer<? super T> action);

该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理。
Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据

简单记:
forEach方法, 用来遍历流中的数据
是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法

    Stream流中的常用方法filter:

用于对Stream流中的数据进行过滤

Stream<T> filter(Predicate<? super. T> predicate);

filter方法的参数Predicote是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
Predicote中的抽象方法:

boolean test(T t);

    Stream流中的常用万法limit: 用于截取流中的元素
    limit方法可以对流进行截取,只取用前n个。
    方法签名:Stream<T> limit(long maxSize);
    参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作
    limit方法是-一个延迟方法,只是对流中的元素进行截取,返回的是-一个新的流,所以可以继续调用Stream流中的其他方法

    如果需要将流中的元素映射到另一个流中,可以使用map方法.

<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该接口需要一个Function函数式接口参数,可以将当前流中的7类型数据转换为另- -种类型的流。
Function中的抽象方法:R apply(T t);

    stream流中的常用方法_ skip:用于跳过元素
    如果希望跳过前几个元素,可以使用skip方法获取一一个截取之后的新流:Stream<T>. skip(long n);
    如果流的当前长度大于n,则跳过前n个;否则将会得到一一个长度为的空流。

    Stream流中的常用方法_ concat :用于把流组合到一起
    如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法

static <T> Stream<T> concat (Stream<? extends T> 0, Stream<? extends T> b)

3、终止操作

​ 一个流只能有一个终结操作,当这个流执行了终结操作时,此时流就会被关闭。无法进行后续操作。

终结方法:
Stream流中的常用方法count :用于统计Stream流中元素的个数

posted @ 2023-02-05 16:51  锐洋智能  阅读(510)  评论(0编辑  收藏  举报