Java8新特性之Lambda表达式和Stream API

Java8新特性之Lambda表达式和Stream API-图1

目录

一.Lambda表达式

1.为什么要使用Lanbda表达式

2.基本介绍

3.具体使用

1.语法格式一:无参无返回值

2.语法格式二:含有一个参数,但无返回值

3.语法格式三:数据类型可以省略,编译器进行类型推断

4.语法格式四:当只含有一个参数的时候,参数小括号可以省略

5.语法格式五:含有两个及以上参数,多条执行语句

6.语法格式六:仅有一条执行语句,return与大括号都可省略

二.函数式(Functional)接口

1.基本介绍

2.Java内置的函数式接口

三.方法引用和构造器引用

1.基本介绍

2.具体使用

1.对象 :: 实例方法

2.类 :: 静态方法  

3.类 :: 非静态方法

 3.构造器引用

4.数组引用

四.Stream API

1.基本介绍

2.Stream操作的三个步骤

 3.Stream的实例化

1.方式一:通过集合

2.方式二:通过数组

3.方式三:通过Stream的of()

4.方式四:创建无限流        -----少用

4.Stream的中间操作

1.筛选与切片               ----中间操作

2.映射               ----中间操作

3.排序               ----中间操作

4.匹配与查找       -----终止操作

5.归约           -----终止操作

6.收集            -----终止操作

五.Optional类

1.基本介绍

2.具体使用


一.Lambda表达式

1.为什么要使用Lanbda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

2.基本介绍

举例:       (o1,o2)->Integer.compare(o1,o2);

格式:

->       : Lambda操作符或箭头操作符
->左边: Lambda形参列表(其实就是接口中的抽象方法的形参列表)                                                  ->右边: Lambda体(其实就是重写的抽象方法的方法体)

本质:作为函数式接口的实例

3.具体使用

1.语法格式一:无参无返回值
    @Test
    public void test01() {
        Runnable run = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱你亲爱的姑娘");
            }
        };
        run.run();
        //上面的匿名函数表达形式可以转化为如下的Lambda表示式
        Runnable run2 = () -> {
            System.out.println("我爱我自己");
        };
        run2.run();

    }

2.语法格式二:含有一个参数,但无返回值
    @Test
    public void test1() {
        Consumer con1 = new Consumer() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("呜呼呼");
        Consumer con2 = (String s) -> {
            System.out.println(s);
        };

        con2.accept("lalala");

    }

3.语法格式三:数据类型可以省略,编译器进行类型推断
    @Test
    public void test2() {
        //因为编译器可以推断出参数的类型为String,因此s的类型可以省略
        Consumer con2 = (s) -> {
            System.out.println(s);
        };

        con2.accept("lalala");

    }

4.语法格式四:当只含有一个参数的时候,参数小括号可以省略
    @Test
    public void test3() {
        //因为只含有一个参数,因此参数的小括号省略到
        Consumer con2 = s -> {
            System.out.println(s);
        };

        con2.accept("lalala");

    }

5.语法格式五:含有两个及以上参数,多条执行语句
    @Test
    public void test4() {
        Comparator cmp1 = new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return Integer.compare(o1, o2);
            }
        };
        System.out.println("*******************");
        Comparator cmp2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return Integer.compare(o1, o2);
        };

    }

6.语法格式六:仅有一条执行语句,return与大括号都可省略
    @Test
    public void test6() {
        Consumer con2 = s -> System.out.println(s);;
        con2.accept("lalala");

    }
    @Test
    public void test5() {
        Comparator cmp1 = new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println("*******************");
        Comparator cmp2 = (o1, o2) -> Integer.compare(o1, o2);

    }

总结:

->左边: Lambda形参列表的参数类型可以省略(类型推断):如果Lambda形参列表只有一个参数,其一对()也可以省略                                                                                                                                ->右边: Lambda体应该使用一对{ }包裹:如果Lambda体只有一条执行语句(可能是return语句),可以省略一对{ }和return语句

二.函数式(Functional)接口

1.基本介绍
  • 如果一个接口中只声明了一个抽象方法,则此接口就叫做函数式接口
  • 可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
  • 我们可以在一个接口上使用@Functionallnterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,,说明这个接口是一个函数式接口。

2.Java内置的函数式接口

四大核心函数式接口

其他接口

三.方法引用和构造器引用 1.基本介绍
  1. 使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
  2. 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
  3. 使用格式: 类(或对象) :: 方法名
  4. 具体分为如下的三种情况:                                                                                                      对象 :: 实例方法                                                                                                                     类 :: 静态方法                                                                                                                         类 :: 非静态方法

2.具体使用

1.对象 :: 实例方法
    //情况一: 对象:: 实例方法
    //Consumer中的void accept(T t)
    //PrintStream中的void println(T t)
    @Test
    public void test1() {
        Consumer con1 = s -> System.out.println(s);
        con1.accept("北京");
        System.out.println("**************");
        PrintStream ps = System.out;
        Consumer con2 = ps::println;
        con2.accept("南京");

    }
    // Supplier中的T get()
    // Employee中的String getName()
    @Test
    public void test2() {
        Employee employee = new Employee(1001, "张三", 25, 6000);
        Supplier sup1 = () -> employee.getName();
        System.out.println(sup1.get());
        System.out.println("******************");
        Supplier sup2=employee::getName;
        System.out.println(sup2.get());

    }

方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!

2.类 :: 静态方法  
    //情况二:类::静态方法
    //Comparator中的int compare(T t1,T t2)
    //Integer中的int compare(T t1,T t2)
    @Test
    public void test3() {
        Comparator cmp1 = (t1, t2) -> Integer.compare(t1, t2);
        System.out.println("***********");

        Comparator cmp2 = Integer::compare;
        System.out.println(cmp2.compare(12, 21));

    }
 //Function中的R apply(T t)
    //Math中的Long round(Double d)
    @Test
    public void test4(){
        Function fun=t->Math.round(t);
        System.out.println(fun.apply(12.65));
        System.out.println("*************");
        Function fun2=Math::round;
        System.out.println(fun.apply(12.65));


    }

3.类 :: 非静态方法
    //情况三:类::实例方法(有难度)
    //Comparator中的int compare(T t1,T t2)
    //String中的int t1.compareTo(t2)
    @Test
    public void test5() {
        Comparator cmp1 = (s1, s2) -> s1.compareTo(s2);

        System.out.println(cmp1.compare("abc", "abd"));
        System.out.println("****************");

        Comparator cmp2 = String::compareTo;

    }
 //BiPredicate中的booLean test(T t1, T t2);
    //String中的booLean t1.equals(t2)
    @Test
    public void test6() {
        BiPredicate bip1 = (s1, s2) -> s1.equals(s2);
        System.out.println(bip1.test("abc", "abc"));
        System.out.println("**********************");

        BiPredicate bip2 = String::equals;
        System.out.println(bip2.test("abc", "abc"));


    }
    //Function中的R apply(T t)
    //Employee中的String getName( );
    @Test
    public void test7() {
        Employee employee = new Employee(1001, "张三", 25, 6000);
        Function fun1 = t -> t.getName();
        System.out.println(fun1.apply(employee));
        System.out.println("******************");
        Function fun2 = Employee::getName;
        System.out.println(fun2.apply(employee));

    }

 3.构造器引用
    //构造器引用
    // Supplier中的T get()
    //Employee的空参构造器: Employee()
    @Test
    public void test8() {
        Employee employee = new Employee(1001, "张三", 25, 6000);
        Supplier sup1 = () -> new Employee();//Lambda表达式
        System.out.println("******************");

        Supplier sup2 = Employee::new; //构造器引用

    }
  //Function中的R apply(T t)
    @Test
    public void test9() {
        Function fun1 = id->new Employee(id);
        System.out.println("***********************");
        Function fun2 = Employee::new;

    }
 //BiFunction中的R apply(T t,U u)
    @Test
    public void test10() {
        BiFunction bif1=(id,name)->new Employee(id,name);
        System.out.println("***************");
        BiFunction bif2=Employee::new;

    }

4.数组引用
    //数组引用          -----把数组看成一个特殊的类
    //Function中的R apply(T t)
    //Function中的R apply(T t)
    @Test
    public void test11() {
        Function fun1 = length -> new String[length];
        String[] apply = fun1.apply(5);
        System.out.println(Arrays.toString(apply));
        System.out.println("***********************");
        Function fun2 = String[]::new;

        String[] apply2 = fun1.apply(5);
        System.out.println(Arrays.toString(apply2));

    }

四.Stream API 1.基本介绍

Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。

集合讲的是数据,Stream讲的是计算!

注意:

  • Stream自己不会存储元素。
  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

2.Stream操作的三个步骤

1-创建Stream
一个数据源(如:集合、数组),获取一个流
2-中间操作
一个中间操作链,对数据源的数据进行处理
3-终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

 3.Stream的实例化

1.方式一:通过集合

default Stream stream() :返回一个顺序流

default Stream parallelStream() :返回一个并行流

    @Test
    public void test1() {
        ArrayList list = new ArrayList();
        list.add(1);list.add(2);list.add(3);list.add(4);
        //default Stream stream() :返回一个顺序流
        Stream stream = list.stream();
        //default Stream parallelStream() :返回一个并行流
        Stream parallelStream = list.parallelStream();

    }

2.方式二:通过数组

调用Arrays类的static Stream stream(T[] array):返回一个流

    //创建Stream方式三:通过stream的of()
    @Test
    public void test3() {
        //调用Arrays类的static  Stream stream(T[] array):返回一个流
        int[] nums={1,2,3,4};
        Stream integerStream = Stream.of(1, 2, 3, 4);
        Stream stringStream = Stream.of("1", "2", "3");

    }

3.方式三:通过Stream的of()
    @Test
    public void test2() {
       //调用Arrays类的static  Stream stream(T[] array):返回一个流
        int[] nums={1,2,3,4};
        IntStream stream = Arrays.stream(nums);
        String[] arr={"123","147","258"};
        Stream stringStream = Arrays.stream(arr);

    }

4.方式四:创建无限流        -----少用

迭代                                                                                                                                           public static Stream iterate(final T seed, final UnaryOperator f)

生成                                                                                                                                                  public static Stream generate(Supplier s)

    @Test
    public void test4() {
        //迭代
        //public static Stream iterate(final T seed, final UnaryOperator f)
        //遍历前十个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
        //生成
        //public static Stream generate(Supplier s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }

4.Stream的中间操作

1.筛选与切片               ----中间操作

    //筛选与切片
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(1);list.add(2);list.add(3);list.add(4);
        //filter(Predicate p)-接收Lambda,从流中排除某些元素。
        //查询list中大于2的数字
        list.stream().filter(e->e>2).forEach(System.out::println);//3 4
        System.out.println("**********************");
        //limit(n)—载断流,使其元素不超过给定数量。
        list.stream().limit(3).forEach(System.out::println);//1 2 3
        System.out.println("**********************");
        //skip(n)—跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(0)互补
        list.stream().skip(3).forEach(System.out::println);//4
        System.out.println("**********************");
        // distinct()—筛选,通过流所生成元素的hashcode()和equals()去除重复元素
        list.add(1); list.add(2);list.add(2);
        list.stream().distinct().forEach(System.out::println);//1 2 3 4

    }

2.映射               ----中间操作

    //映射
    @Test
    public void test2(){
        //map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        List list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(s->s.toUpperCase()).forEach(System.out::println);
        System.out.println("********************");

        //flatMap(Function f)——接收一个函数作为参数,将流中的每个值都换成另一个流然后把所有流连接成一个流。
        list.stream().flatMap(StreamTest2::fromStringToStream).forEach(System.out::println);

    }
    public static Stream fromStringToStream(String s){
        ArrayList list = new ArrayList();
        for (char c : s.toCharArray()) {
            list.add(c);
        }
        return list.stream();

    }

3.排序               ----中间操作

    //排序
    @Test
    public void test3(){
        ArrayList list = new ArrayList();
        list.add(12);list.add(10);list.add(36);list.add(20);list.add(1);list.add(6);
        //sorted()——自然排序
        list.stream().sorted().forEach(System.out::println);
        System.out.println("*******************************");
        //sorted( comparator com)——定制排序
        list.stream().sorted((o1,o2)->Integer.compare(o2,o1)).forEach(System.out::println);

    }

4.匹配与查找       -----终止操作

    //匹配与查找
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(1);list.add(2);list.add(3);list.add(4);
//        aLLMatch(Predicate p)—检查是否匹配所有元素。
        boolean b = list.stream().allMatch(s -> s > 0);
        System.out.println(b);//true
//        anyMatch(Predicate p)—检查是否至少匹配一个元素。
        boolean b1 = list.stream().anyMatch(s -> s == 2);
        System.out.println(b1);//true
//        noneMatch(Predicate p)—检查是否没有匹配的元素。
        boolean b2 = list.stream().noneMatch(s -> s == 5);
        System.out.println(b2);//true
//        findFirst——返回第一个元素
        Optional first = list.stream().findFirst();
        System.out.println(first);//Optional[1]
//        findAny——返回当前流中的任意元素
        Optional any = list.parallelStream().findAny();
        System.out.println(any);//Optional[3]
//        count—-返回流中元素的总个数
        long count = list.stream().count();
        System.out.println(count);//4
//        max (Comparator c)—返回流中最大值练习:返回最高的工资:
        Optional max = list.stream().max((o1, o2) -> Integer.compare(o1, o2));
        System.out.println(max);//Optional[4]
//        min(Comparator c)—返回流中最小值练习:返回最低工资的员工
        Optional min = list.stream().min((o1, o2) -> Integer.compare(o1, o2));
        System.out.println(min);//Optional[1]
//        forEach(Consumer c)一内部迭代
        list.stream().forEach(System.out::println);//1 2 3 4

        list.forEach(System.out::println);//1 2 3 4

    }

5.归约           -----终止操作

    //归约
    @Test
    public void test2() {
        // reduce(T identity,BinaryOperator)-中元素反复结合起来,得到一个值。返回T
        //练习:计算1-10的和
        List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream().reduce(0, Integer::sum);//identity为初始值
        System.out.println(sum);//55
        //reduce(BinaryOperator)一可以将流中元素反复结合起来,得到一个值。返回optional
        Optional reduce = list.stream().reduce(Integer::sum);
        System.out.println(reduce);//Optional[55]
        
    }

6.收集            -----终止操作

    //收集
    @Test
    public void test3() {
//      collect(Collector c)将流转换为其他形式。接策一个Collector接口的实现,用于给Stream中元素做汇总的方法
        List list = Arrays.asList(4, 5, 6, 7, 7, 8, 8);
        List collect = list.stream().filter(s -> s > 5).collect(Collectors.toList());
        System.out.println(collect);//6,7,7,8,8
        System.out.println("********************");
        Set collect1 = list.stream().filter(s -> s > 5).collect(Collectors.toSet());
        System.out.println(collect1);//6,7,8

    }

五.Optional类 1.基本介绍

Optional类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在 Optional可以更好的表达这个概念。并且可以避免空指针异常。

2.具体使用

Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

  • 创建Optional类对象的方法:

Optional.of(T t):创建一个 Optional实例,t必须非空;

Optional.empty():创建一个空的Optional 实例
Optional.ofNullable(T t):t可以为null

  • 判断Optional容器中是否包含对象:

boolean isPresent():判断是否包含对象
void ifPresent(Consumerconsumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

  • 获取Optional容器的对象:

Tget():如果调用对象包含值,返回该值,否则抛异常
T orElse(T other):如果有值则将其返回,否则返回指定的other对象。
T orElseGet(Supplier other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
T orElse Throw(SupplierexceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

 

转载请说明出处 内容投诉内容投诉
南趣百科 » Java8新特性之Lambda表达式和Stream API

南趣百科分享生活经验知识,是您实用的生活科普指南。

查看演示 官网购买