Java 8 新特性 | 总结

2022-10-27 10:41:32 浏览数 (2)

一、Lambda表达式

1、函数式接口

如果说,一个接口中,要求实现类必须实现的抽象方法,有且只有一个!这样的接口就是函数式接口*注:接口里的方法有default修饰(有方法体),子类可以重写也可以不重写

代码语言:javascript复制
//非函数式接口,Object类中有默认的toString方法,可以不重写
interface Test{
   String toString();
}

2、@FunctionalInterface注解

用在接口之前,判断这个接口是否是一个函数式接口。如果是函数式接口,没有任何问题。如果不是函数式接口,则会报错。

代码语言:javascript复制
@FunctionalInterface
interface FunctionalInterfaceTest{
    void test();
}

3、基础语法

代码语言:javascript复制
(参数类型 参数,参数类型 参数)->{
  方法体
};

4、语法进阶

(1)参数的类型可以不写,在接口方法中已经定义过。

(2)如果需要省略参数的类型,要保证:要省略,每一个参数的类型都必须省略不写。绝对不能出现,有的参数类型省略了,有的参数类型没省略

代码语言:javascript复制
//多个参数、无返回值的方法实现
NoneReturnMutipleParameter lambda1=(a,b)->{
    System.out.println("多个参数、无返回值方法的实现:参数a是" a ", 参数b是" b);
}

(3)如果参数列表中的参数数量有且只有一个,此时,参数列表的小括号是可以省略不写的,省略小括号的同时必须省略参数的类型

代码语言:javascript复制
//有参、无返回值的方法实现
NoneReturnSingleParameter lambda2=a->{
    System.out.println("一个参数、无返回值方法的实现:参数是 "   a);
}

(4)当一个方法体中的逻辑,有且只有一句的情况下,大括号可以省略

代码语言:javascript复制
//有参、无返回值的方法实现
NoneReturnSingleParameter lambda2=a->System.out.println("一个参数、无返回值方法的实现:参数是 "   a);

(5)如果一个方法中唯一的一条语句是一个返回语句,此时在省略大括号的同时,也必须省略return

代码语言:javascript复制
SingleReturnMultipleParameter lambda3=(a,b)->a b;

5、函数引用:引用一个已经存在的方法,使其替代lambda表达式完成接口的实现

(1)静态方法的引用

  • 语法 类::静态方法
  • 注意事项:引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致
代码语言:javascript复制
public class Syntax1 {
    public static interface Calculate{
        int calculate(int a,int b);
    }

    //静态方法的引用
    public static void main(String[] args){
        //实现一个多个参数的、一个返回值的接口
        //对一个静态方法的引用
        Calculate lambda1=Syntax1::calculate;
        System.out.println(lambda1.calculate(,));
    }

    private static int calculate(int x,int y){
        if(x>y){
            return x-y;
        }else if(x<y){
            return y-x;
        }
        return x y;
    }
}

(2)非静态方法的引用

  • 语法 对象::非静态方法
  • 引用的这个方法,参数(数量、类型)和返回值,必须要跟接口中定义的一致
代码语言:javascript复制
public class Syntax1 {
    public static interface Calculate{
        int calculate(int a,int b);
    }

    //静态方法的引用
    public static void main(String[] args){
        //实现一个多个参数的、一个返回值的接口
        //对一个静态方法的引用
        Calculate lambda1=Syntax1::calculate;
        System.out.println(lambda1.calculate(,));
        //对一个非静态方法的引用
        Calculate lambda2=new Syntax1()::calculate2;
        System.out.println(lambda2.calculate(,));
    }

    private int calculate2(int a,int b){
        if(a!=b){
            return a-b;
        }else{
            return a b;
        }
    }

    private static int calculate(int x,int y){
        if(x>y){
            return x-y;
        }else if(x<y){
            return y-x;
        }
        return x y;
    }
}

(3)构造方法的引用

  • 语法 类名::new
  • 可以通过接口中的方法的参数,区分引用不同的构造方法
代码语言:javascript复制
public class Lambda2 {
    public static class Person{
        String name;
        int age;
        public Person(){
            System.out.println("Person类的无参构造方法执行了");
        }
        public Person(String name){
            this.name=name;
            System.out.println("Person类的有参数构造方法执行了");
        }
        public Person(String name,int age){
            this.name=name;
            this.age=age;
            System.out.println("Person类的两个参数构造方法执行了");
        }
    }

    private interface GetPersonWithNoneParameter{
        Person get();
    }

    private interface GetPersonWithSingleParameter{
        Person get(String name);
    }

    private interface GetPersonWithMultipleParameter{
        Person get(String name,int age );
    }

    public static void main(String[] args){
        GetPersonWithNoneParameter getPerson=Person::new;
        getPerson.get();
        GetPersonWithSingleParameter getPerson1=Person::new;
        getPerson1.get("张三");
        GetPersonWithMultipleParameter getPerson2=Person::new;
        getPerson2.get("张三",);
    }
}

(4)对象的特殊用法

  • 如果lambda表达式中包含了某一个对象,此时方法体中,直接使用这个对象调用它的某一个方法就可以完成整体的逻辑。其他的参数可以作为调用方法的参数。此时可以简化为 类::方法,方法不加括号
代码语言:javascript复制
public class Lambda3 {
    public static class Person{
        private String name;

        public String getName() {
            return name;
        }

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

    public interface MyInterface{
        //String get(Person person);
        void set(Person person,String name);
    }

    public static void main(String[] args){
        Person xiaoming=new Person();
        xiaoming.setName("xiaoming");

//        MyInterface lambda1=x->x.getName();
//        MyInterface lambda2=Person::getName;
//        System.out.println(lambda2.get(xiaoming));

        MyInterface lambda3=(x,n)->x.setName(n);
        MyInterface lambda4=Person::setName;
        lambda4.set(xiaoming,"123");
        System.out.println(xiaoming.getName());

    }
}

(5)lambda表达式注意事项

代码语言:javascript复制
public class Lambda5 {
    private static int y=;
    public static void main(String[] args){
        //1.定义一个局部变量
        int x=;
        //2.使用lambda表达式实现接口
        LambdaTest lambda=()->{
            System.out.println("x=" x);
            System.out.println("y=" y);
        };
        //3.修改变量x的值(此处是局部变量,不能更改值,不注销)
        //x=20;
        //4.修改变量y的值
        y=;
    }
}

二、集合的流式编程

  • 简介:把数据源中的数据读到Stream流里面,对Stream流里面的数据进行操作(删除、过滤、映射等),每次操作结果也是一个流对象,可以对这个流再进行其他的操作,最后将Stream流里的数据放到集合或者数组里。
  • 流式编程的步骤

(1)获取数据源,将数据源中的数据读取到流中

(2)对流中的数据进行各种各样的处理

(3)对流中的数据进行整合处理

其中(2)称为中间操作,(3)称为最终操作。

1、数据源的获取

(1)数据源的简介

*注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流的数据进行处理、过滤、映射、排序等,此时是不会影响数据源中的数据的

(2)数据源的获取

代码语言:javascript复制
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 集合流式编程中的数据源的读取
 * 读取数据源中的数据,得到一个流对象
 */
public class DataSource {
    public static void main(String[] args){
        collectionDataSource();
        arrayDataSource2();
    }

    /**
     * 将list作为数据源,读取list中的数据到一个流中
     */
    public static void collectionDataSource(){
        //1.实例化一个集合
        List<Integer> list=new ArrayList<>();
        //2.填充元素
        Collections.addAll(list,,,,,,,,,,);
        //3.读取集合中的数据,将其读取到流中
        Stream<Integer> stream=list.stream();
        //4.输出stream
        System.out.println(stream);
    }

    public static void arrayDataSource(){
        //1.实例化一个数组
        Integer[] array=new Integer[]{,,,,,,,,,};
        //2.读取数组中的数据到流中,得到一个流对象
        Stream<Integer> stream= Arrays.stream(array);
        //3.输出stream
        System.out.println(stream);
    }

    public static void arrayDataSource2(){
        //1.实例化一个数组
        int[] array=new int[]{,,,,,,,,,};
        //2.读取数组中的数据到流中,得到一个流对象
        IntStream stream= Arrays.stream(array);
        //3.输出stream
        System.out.println(stream);
    }
}

2、最终操作

(1)将流中的数据收集到一起,对这些数据进行一些处理,最常见的处理,就是将流中的数据存入一个集合。

*注意:最终操作,之所以叫最终操作,是因为,在最终操作执行结束后,会关闭这个流,流中的所有数据都会销毁。如果使用一个已经关闭了的流,会出现异常。

(2)collect:将流中的元素放到集合里

代码语言:javascript复制
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 最终操作
 */
public class FinalOperation {
    public static void main(String[] args){
        collectUsage();
    }
    /**
     * 最终操作:collect
     */
    public static void collectUsage(){
        //1.获取数据源
        Stream<Integer> dataSource=getDataSource();
        //2.流中的数据的聚合
        //List<Integer> list=dataSource.collect(Collectors.toList());
        Map<String,Integer> list=dataSource.collect(Collectors.toMap(i->i.toString(), i->i));
        System.out.println(list);
    }
    /**
     * 数据源的获取,从一个容器中获取数据源中的数据
     * @return读取数据源中的数据,得到一个Stream对象
     */
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource=new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource,,,,,,,,,,);
        //3.读取数据源中的数据,得到Stream对象并返回
        return dataSource.stream();
    }
}

(3)reduce:将流中的数据按照一定的规则聚合起来

代码语言:javascript复制
//将流的元素,逐一带入到这个方法中,进行运算
//最终的运算结果,得到的其实是一个Optional类型,需要使用get()获取到里面的数据
int result=list.stream().reduce((e1,e2)->e1 e2).get();
System.out.println(result);

(4)count:统计流中元素的数量

代码语言:javascript复制
long result=list.stream().count();
System.out.println(result);

(5)forEach:迭代、遍历流中的数据

代码语言:javascript复制
list.stream().forEach(System.out::println)

(6)max&&min

代码语言:javascript复制
list.stream().min(Integer::compareTo).get();

(7)Matching

  • allMatch:只有当流中所有元素,都匹配指定的规则,才会返回true
  • anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
  • noneMatch:只有当流中的所有的元素,都不满足指定的规则,才会返回true
代码语言:javascript复制
//判断流中是否所有的元素都大于50
boolean result=list.stream().allMatch(ele->ele > );
//判断流中是否有大于50的数据
boolean result=list.stream().anyMatch(ele->ele > );
//判断流中是否都是偶数
boolean result=list.stream().noneMatch(ele->ele%!=);

(8)find

  • findFirst:从流中获取一个元素(获取的是开头的元素)
  • findAny:从流中获取一个元素(一般情况下,是获取的开头的元素) 这两个方法,绝大部分情况下,是完全相同的,但是在多线程的环境下,这两个返回的结果可能不一样。
代码语言:javascript复制
Integer integer=list.stream().findFirst().get();
Integer integer=list.stream().findAny().get();

(9)IntStream的使用

代码语言:javascript复制
int[] array=new int[]{,,,,,,,,,};
IntStream stream=Arrays.stream(array);
System.out.println(stream.max().getAsInt());
System.out.println(stream.min().getAsInt());
System.out.println(stream.sum());
System.out.println(stream.count());
System.out.println(stream.average().getAsDouble());
//获取到一个对流中的数据的分析结果
IntSummaryStatistics intSummaryStatistics=stream.summaryStatistics();
System.out.println("max = " intSummaryStatistics.getMax());
System.out.println("min = " intSummaryStatistics.getMin());
System.out.println("sum = " intSummaryStatistics.getSum());
System.out.println("average = " intSummaryStatistics.getAverage());
System.out.println("count = " intSummaryStatistics.getCount());

3、中间操作:将数据从数据源中读取到流中,中间操作就是对流中的数据进行各种各样的操作、处理。中间操作可以连续操作,每一个操作的返回值都是一个Stream对象,可以继续进行其他的操作,直到最终操作。

(1)filter:条件过滤,仅保留流中满足指定条件的数据,其他不满足的数据都会被删除

(2)distinct:去除流中重复的数据,需要重写对象的hashCode和equals方法

(3)limit&&skip:limit表示截取流中指定数量的数据,skip表示跳过指定数量的数据,截取剩余的部分

(4)map:对流中的数据进行映射,用新的数据替换旧的数据

代码语言:javascript复制
list.stream().map(ele->ele ".txt").forEach(System.out::println);
IntSummaryStatistics intSummaryStatistics=dataSource.mapToInt(Student::getScore).summaryStatistics();

4、Collectors工具类

Collectors 类提供了大量方法用于指示如何收集元素。

比如 Collectors.toList() 方法可以将流中的元素收集起来,并转换为列表

代码语言:javascript复制
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("Filtered List: "   filtered);

比如 Collectors.joining() 方法可以将流中的元素收集起来,并使用指定的字符串拼接符拼接成一个字符串。

代码语言:javascript复制
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: "   mergedString);

0 人点赞