JAVA12-Lambda表达式与集合的流式编程

1.Lambda表达式

1.1 Lambda表达式简介

Lambda表达式是 jdk1.8 引入的一个新特性,它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性之一。

特点:

  • Lambda表达式的引入简化了匿名内部类的语法,让代码更加简洁明了。

  • Lambda表达式提供了一种便捷的语法形式,使得函数可以作为参数传递给方法或者作为返回值返回

  • Lambda表达式的引入使得Java在并行编程方面具备了更好的支持

  • lambda表达式本质来讲,是一个匿名函数(匿名方法)

1.2 Lambda基础语法

2.1 语法与解析

语法

(parameters) -> expression       或        (parameters) -> { statements;}

解析:

  • 箭头(->)将参数与Lambda主体分隔开来

  • 参数部分:

    • 参数可以是任意合法的Java参数列表,可以为空或包含一个或多个参数

    • 参数列表的类型名可以省略 不能出现有些省略了,有些没有省略的情况

    • 如果参数列表中,参数的数量有且只有一个,则小括号可以省略

  • Lambda主体:

    • Lambda主体可以是一个表达式,表达式外的大括号,可加可不加没有大括号时,return关键字必须省略。

    • 也可以是一个代码块。将按照常规的Java语法执行可能需要使用return语句来返回值。

 2.2 语法案例

语法:

1. 无参数的Lambda表达式:

        () -> System.out.println("Hello, Lambda!");

2. 带有参数的Lambda表达式:

        (int m) -> System.out.println(m);

        或 (m) -> System.out.println(m);

        或 m  -> System.out.println(m); ​ ​

        (int x, int y) -> System.out.println(x + y);

        或者 (x, y) -> System.out.println(x + y);

3. 带有多行代码的Lambda表达式:

        (x, y) -> {    int sum = x + y;    

                           System.out.println("Sum: " + sum);    

                           return sum; }

1.3 Lambda的应用

3.1 初窥门径

应用场景:lambda表达式,只能作用于函数式接口

                 函数式接口:有且只有一个抽象方法的接口

 引入案例代码(匿名内部类用Lambda表达式的写法)

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class _01InnerClassDemo {
    public static void main(String[] args) {
        List<Person> ps = new ArrayList<>();
        ps.add(new Person("张三", 20));
        ps.add(new Person("李四", 30));
        ps.add(new Person("王五", 40));
        ps.add(new Person("赵六", 50));
//        Comparator c = new Comparator<Person>() {
//            @Override
//            public int compare(Person o1, Person o2) {
//                return o1.getAge()-o2.getAge();
//            }
//        };
//        Comparator<Person> c = (o1,o2) -> o2.getAge()-o1.getAge();
//        Collections.sort(ps,c);
        Collections.sort(ps,(o1, o2) -> o2.getAge()-o1.getAge());
        System.out.println(ps);

    }
}


class Person implements Comparable<Person>{
    private String name;
    private int age;

    public Person(){

    }
    public Person(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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Person o) {
        return age-this.age;
    }
}

 3.2 登堂入室

Lambda表达式的应用:

        1.Lambda表达式实际上就是匿名内部类的简化版本

        2.Lambda表达式是JDK1.8引入的一个最重要的新特性另一个就是集合的流式编程。         3.Lambda表达式是java为了扩展函数式编程引入的。

        4.Lambda表达式可以理解为是一个匿名函数(匿名方法:方法没有名字)

        5.Lambda表达式只能作用于函数式接口有且只有一个抽象方法的接口(可以有静态方法,默认方法,静态常量等)

 案例演示

public class _02LambdaDemo01 {
    public static void main(String[] args) {
        //2.测试类实现
        Test1 test1 = new Test1();
        test1.print();
        //3.使用匿名内部类的方式,实现NoParameterNoReturn接口,打印"我一定能学会java"
        NoParameterNoReturn npnr = new NoParameterNoReturn() {
            @Override
            public void print() {
                System.out.println("我一定能学会java");
            }
        };
        npnr.print();
        //4.使用lambda表达式,实现NoParameterNoReturn接口,打印"哈哈哈,我哭了...";
        NoParameterNoReturn npnr2 = ()-> System.out.println("哈哈哈,我哭了...");
        npnr2.print();
        //5.使用lambda表达式,实现OneParameterNoReturn接口,打印"'我喜欢'+形参",并测试打印,传入'苹果'
        OneParameterNoReturn oneturn = a -> System.out.println("我喜欢"+a);
        oneturn.print("苹果");
        //6.使用lambda表达式,实现MuilParameterNoReturn接口,打印两个参数拼接的效果,测试传入"我今年","18"
        MuilParameterNoReturn mpnr = (a,b)-> System.out.println(a+b);
        mpnr.print("我今年",18);
        //7.使用lambda表达式,实现NoParameterReturn接口,计算两个随机数,区间[25,40]的和",测试。
        NoParameterReturn npr = ()-> {
            int a=(int) (Math.random()*16+25);
            int b=(int) (Math.random()*16+25);
            return a+b;
        };
        System.out.println("两个随机数的和"+npr.calculate());
        //8.使用lambda表达式,实现OneParameterReturn接口,计算形参的立方,测试传入3
        OneParameterReturn opr = a -> a*a*a ;
        System.out.println("3的立方: "+opr.calculate(3));
        //9.使用lambda表达式,实现MuilParameterReturn接口,计算两个形参的立方和,测试传入3和4
        MuilParameterReturn mpr = (a,b) -> a*a*a+b*b*b;
        System.out.println("3的立方和4的立方的和:"+mpr.calculate(3,4));



    }
}

//1.使用实现类的方式,实现NoParameterNoReturn接口,打印"java编程真简单"
class Test1 implements NoParameterNoReturn {
    @Override
    public void print() {
        System.out.println("java编程真简单");
    }
}


// 里面的抽象方法,没有形参,也没有返回值。
interface NoParameterNoReturn{
    void print();
}
//一个形参,没有返回值
interface OneParameterNoReturn{
    void print(String info);
}
//多个形参,没有返回值
interface MuilParameterNoReturn{
    void print(String info,int age);
}
//没有形参,有返回值
interface NoParameterReturn{
    int calculate();
}
//一个参数,带返回值
interface OneParameterReturn{
    int calculate(int a);
}
//多个形参,带返回值。
@FunctionalInterface  //注解是用来校验是否为函数式接口(就是接口里面是否只有一个抽象方法)
interface MuilParameterReturn{
    double PI =3.14;
    int calculate(int a,int b);

}

结果:

 3.3 Lambda表达式在集合中的应用

        Lambda表达式在Collection接口中的使用主要涉及对集合进行迭代、筛选和转换等操作。在Java 8及以上的版本中,Collection接口增加了一些默认方法,例如forEach()removeIf()stream()等,使得使用Lambda表达式更加方便。

使用条件:

第一个:排序时,使用比较器的时候

第二个:迭代时

第三个:根据条件删除元素

案例代码: 

import java.util.*;

public class _03LambdaDemo02_InList {
    public static void main(String[] args) {
        //测试第一种:集合的排序
        List<String> list = new ArrayList<String>();
        list.add("michael");
        list.add("david");
        list.add("peter");
        list.add("bob");
        list.add("lucy");
        System.out.println(list);
        //按照字符串长度降序:比较器使用了lambda表达式的方法
        Collections.sort(list,(a,b)->b.length()-a.length());
        System.out.println(list);

        //测试第二种:集合的迭代
        Integer[] arr = new Integer[]{1,2,3,4,5};
        List<Integer> nums = Arrays.asList(arr);
        //forEach方法
        /*
            forEach(Consumer c)的源码:
                for(T t:this){
                    c.accept(t);
                }
            Consumer是一个函数式接口:里面的抽象方法
                void accept(T t)

            因此只需要向forEach()方法中传入 accept的匿名函数,也就是lambda表示即可
         */
        nums.forEach(num->System.out.println(num));
        System.out.println("-------------------------------");
        //继续简化
        nums.forEach(System.out::println);

        System.out.println("-----------set的迭代--------------");
        //set接口的迭代
        Set<Integer> set = new HashSet<>(nums);
//        System.out.println(set);

        set.forEach(System.out::println);
        System.out.println("-----------map的迭代--------------");
        Map<String, Integer> map = new HashMap<>();
        map.put("michael", 20);
        map.put("david", 30);
        map.put("peter", 40);
        map.put("bob", 50);
        map.put("lucy", 60);
        System.out.println(map);

        //key的迭代
        map.keySet().forEach(key->System.out.println(key+":"+map.get(key)));
        map.keySet().forEach(System.out::println);
        //entrySet的迭代
        map.entrySet().forEach(e-> System.out.println(e.getKey()+"-->"+e.getValue()));
        map.entrySet().forEach(System.out::println);
        //values的迭代
        map.values().forEach(System.out::println);

        /*
            根据条件删除元素
         */
        List <Integer> list2 = Arrays.asList(18,17,39,5,17);
        List <Integer> list3 = new ArrayList<>(list2);

        /*
            removeIf(Predicate filter):
            源码解析
                内部逻辑就是一个迭代器遍历集合,根据条件做删除操作
                条件就是filter的test方法。
            Predeicate 是一个函数式接口,里面有boolean test(T t)方法,因此我们在使用时就是写一个lambda表达式,来实现test方法即可。

         */
        list3.removeIf(m->m.equals(17));

    }
}

1.4 变量的捕获

在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(Variable Capturing)。

变量的捕获: 在内部对外部的变量的引用和访问
    1. 实例变量(成员变量,属性,全局变量)
    2. 静态变量
    3. 方法形参: 访问的方法形参也只能访问,不能覆盖。
    4. 本地变量(局部变量):内部类可以捕获并访问声明为final的本地变量。从Java 8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)。

    总结:
    1.匿名内部类访问的局部变量(方法形参,本地变量)都是只能访问,不能覆盖
    2.lambda表达式也可以访问上述四种变量,依然是对局部变量只能访问,不能覆盖

 代码演示:

public class _01InnerClassDemo {
    private int a;  //实例变量
    private static int b;   //静态变量
    static {
        b=2;
    }

    public _01InnerClassDemo() {
        a = 1;
    }

    public void M1(int c){
        int d = 4;
        MyTest mt = new MyTest() {
            @Override
            public void test1() {
                //访问外部类的成员变量:外部类名.this.成员变量 或者直接写。
                System.out.println("成员变量(instance variable):"+a);
                //访问外部类的静态变量: 外部类名.静态变量, 或者直接写。
                System.out.println("static variable: "+b);
                //匿名内部类访问的方法形参也只能访问,不能覆盖。
                System.out.println("method parameter: "+c);
                // 匿名内部类访问的局部变量,是默认被final修饰的。final修饰的变量只能初始化一次。
                System.out.println("native variable: "+d);
            }
        };
        mt.test1();
    }
    public void m2(int c){
        int d = 4;
        MyTest mt = () -> {
            //访问外部类的成员变量:外部类名.this.成员变量 或者直接写。
            System.out.println("成员变量(instance variable):"+a);
            //访问外部类的静态变量: 外部类名.静态变量, 或者直接写。
            System.out.println("static variable: "+b);
            //访问的方法形参也只能访问,不能覆盖。
            System.out.println("method parameter: "+c);
            //访问的局部变量,是默认被final修饰的。final修饰的变量只能初始化一次。
            System.out.println("native variable: "+d);

        };
        mt.test1();

    }

    public static void main(String[] args) {
        _01InnerClassDemo demo = new _01InnerClassDemo();
//        demo.M1(1);
        demo.m2(3);
    }


}

interface MyTest{
    void test1();
}

2. 集合的流式编程

2.1 流式编程的简介

1)Stream编程的简介

        Stream是JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一。(另外一个是 lambda表达式)。

        Stream是对集合操作的增强流不是集合的元素不是一种数据结构,不负责数据的存储的。流更像是 一个迭代器可以单向的遍历一个集合中的每一个元素,并且不可循环

 2)为什么要使用集合的流式编程

        有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果。在这个过程中,集合的流式编程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行操作(删除、过滤、映射...)。每次的操作结果也是一个流对象,可以对这个流再进行其他的操作

3)使用流式编程的步骤

通常情况下,对集合中的数据使用流式编程,需要经过以下三步。

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

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

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

在上述三个过程中,

        过程2中,有若干方法,可以对流中的数据进行各种各样的操作,并且返回流对象本身,这样的操作,被称为 -- 中间操作

        过程3中,有若干方法,可以对流中的数据进行各种处理,并关闭流,这样的操作,被称为 -- 最终操作

        在中间操作和最终操作中,基本上所有的方法参数都是函数式接口,可以使用lambda表达式来实现。 使用集合的流式编程,简化代码量,需要大量使用 lambda 表达式。

 2.2 数据源的获取

1)数据源的介绍

        数据源,顾名思义,既是流中的数据的来源。是集合的流式编程的第一步将数据源中的数据读取到流中,进行处理。注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序... ,此时是不会影响数据源中的数据的 。  

2) 数据源的获取

        这个过程,其实是将一个容器中的数据,读取到一个流中。因此无论什么容器作为数据源,读取到流中 的方法返回值一定是一个Stream。

数据源的获取
    集合的流式编程:
    1.传统方式,如果对集合中的元素做处理时,可能要书写大量的代码,比如增加,删除,过滤等
    2.集合的流式编程:是JDK1.8引入的两个重要特性之一。
    3.集合的流逝编程是对传统方式的一种简化操作。
    4.集合的流式变成,分三步:
        --第一步: 获取数据源(关联数据源),返回Stream对象
        --第二步: 对Stream对象进行各种处理,处理后的结果依然是Stream对象
        --第三步: 对Stream对象的最后整合处理。处理后的结果一般情况下不再是Stream对象,可能是一个具体的数字,字符串,或者是一个新的集合。
        --注意: 整个过程中,数据源本身并不会发生变化

 代码演示(获取数据源):

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class _01DataSourceGet {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        /*
        如果想要对这个集合进行流式编程,第一步,必须获取数源(关联数据源)
         */


        //1.获取的流对象,是串行的,不是并行的,好比只有一个人去工作。
        Stream<Integer> s1 = list.stream();
        //2. 获取的流对象,是并行的,好比有多个人同时工作。效率高。
        Stream<Integer> integerStream = list.parallelStream();


    }
}

2.3 最终操作

1) 最终操作的简介

        将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历、数据统计... ,通过 最终操作,需要掌握如何从流中提取出来我们想要的信息。

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

2)Collect

集合的流式编程的最终操作:
    1.将流中的数据整合到一起。可以存入一个新的集合,也可以遍历,或者统计。
    2. 最终操作,会关闭这个流,流里的数据都会被销毁。如果在关闭流的基础上,继续操作流,会报如下错误
        stream has already been operated upon or closed

    最终操作常用的方法如下:
    1.collect: 搜集方法,可以将流的数据搜集成一个新的集合
                该方法的形参是一个Collector接口(非函数式接口),可以用来指定搜集规则。
                通常情况下,不需要程序员自己实现,Collectors工具类里提供的方法够用。

 Collect方法代码演示:

public class _02Final_collect {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);

        //获取数据源
        Stream<Integer> stream = nums.stream();
        //搜集1: 搜集成List集合
//        List<Integer> c1 =stream.collect(Collectors.toList());
        //搜集2: 搜集成Set集合
//        Set<Integer> c2 = stream.collect(Collectors.toSet());
//        System.out.println(c2);
        //搜集3 搜集成Map集合
        /*
            Collectors.toMap(keyMapper,valueMapper)
            keyMapper是一个函数式接口,里面有一个R apply(T t)抽象方法,我们就是通过lambda表达式来重写apply方法
            valueMapper亦如此。
         */
        Map<String, Integer> c3 = stream.collect(Collectors.toMap((e) -> "key" + e, e -> e));
        System.out.println(c3);

    }
}

3)reduce 

2. reduce方法:将流中的数据按照一定的规则聚合起来

代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class _03Final_reduce {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        Stream<Integer> stream = nums.stream();
        //计算数据源的元素之和   方法参数也是lambda表达式: 对应的抽象方法 R apply(T t ,U u);
        // 返回的类型:Optional,需要调用它的get方法,获取里面的数据。

//        Optional<Integer> reduce = stream.reduce((a, b) -> a + b); //15
        /*
            从下面的案例可以得出结论: a变量接收的是数据源中的第一个元素,然后b变量接收的是剩下的元素。
                                 a -= b;
                                 a =- b;
         */
        Optional<Integer> reduce = stream.reduce((a, b) -> a - b);// -13
        int result = reduce.get();
        System.out.println("计算结果:"+result);
    }
}

 4)count

 count方法:统计流中的元素数量。

count测试代码 

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class _04Final_count {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        Stream<Integer> stream = nums.stream();
        /*
            count(): 用于统计数据源的元素个数。
                底层源码: return mapToLong(e -> 1L).sum();
                    即将元素映射成1L,然后求和。
         */
        long count = stream.count();
        System.out.println(count);
    }
}

 5)forEach Max Min

forEach方法:迭代、遍历流中的数据。

Max 方法:获取流中的最大的元素。

Min 方法:获取流中的最小的元素。

测试代码:

package com.se.day08.cStream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class _05Final_forEach_max_min {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        Stream<Integer> stream = nums.stream();
        /*
            forEach方法:对流中的数据进行遍历,注意遍历完毕,流就关闭了。
         */
        stream.forEach(num -> System.out.println(num));
//        stream.forEach(System.out::print);

        /*
            max(Comparator c):
                获取排序后的最后一个元素
         */

        Integer integer = nums.stream().max((a, b) -> a-b).get();
        System.out.println(integer);
        /*
            min(Comparator c):
                获取排序后的第一个元素
         */
        Integer integer2 = nums.stream().min((a, b) -> a - b).get();
        System.out.println(integer2);
    }
}

6)Matching

allMatch: 只有当流中所有的元素,都匹配指定的规则,才会返回 true

anyMatch: 只要流中有任意的数据,满足指定的规则,都会返回 true

noneMatch: 只有当流中的所有的元素,都不满足指定的规则,才会返回true

package com.se.day08.cStream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/*
    AllMatch:   当数据源中的所有元素都满足匹配条件,才返回true。
    AnyMatch:   当数据源中的任意一元素满足匹配条件,就返回true。
    NoneMatch:  当数据源中的所有元素都不满足匹配条件,返回true。

 */
public class _06Final_Matching {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        Stream<Integer> stream = nums.stream();
        boolean b = stream.allMatch(a -> a < 10);
        System.out.println("allMatch测试: "+b);
        Stream<Integer> stream1 = nums.stream();
        boolean b1 = stream1.anyMatch(a-> a <2);
        System.out.println("anyMatch测试: "+b1);
        Stream<Integer> stream2 = nums.stream();
        boolean b2 = stream2.noneMatch(a-> a <0);
        System.out.println("noneMatch测试: "+b2);
    }

}

7)find

findFirst: 从流中获取一个元素(一般情况下,是获取的开头的元素)

findAny: 从流中获取一个元素(一般情况下,是获取的开头的元素)

这两个方法,绝大部分情况下,是完全相同的,但是在多线程的环境下, findAny和find返回的结果可能不一样

 测试代码

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class _07Final_find {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        Stream<Integer> stream = nums.stream();
        //串的流演示
        Optional<Integer> first = nums.stream().findFirst();
        int e1 = first.get();
        System.out.println(e1);
        int e2 = nums.stream().findAny().get();
        System.out.println(e2);

        //并行的流
        Integer e3 = nums.stream().findFirst().get();
        Integer e4 = nums.stream().findAny().get();
        System.out.println("e3 " + e3+",e4 "+e4);
    }
}

2.4 中间操作

1)中间操作的简介

        中间操作是流式处理中的步骤,它们会返回流本身,允许链式调用多个操作。这些操作通常是惰性的,意味着它们不会立即执行,而是等待终端操作触发时才开始处理数据

        中间操作是流式编程中构建复杂数据处理管道的关键。通过链式调用多个中间操作,可以灵活地处理集合中的数据,而无需编写复杂的迭代逻辑。然而,请注意,中间操作本身不会执行任何数据处理;它们只是定义了数据处理的步骤,等待终端操作触发时才开始执行。

2)filter 与distinct 

filter:通过给定的谓词(一个返回布尔值的函数)过滤流中的元素。

distinct :去重

演示代码:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class _01Filter_distinct {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(1);
        nums.add(2);
        nums.add(3);
        nums.add(4);
        nums.add(5);
        nums.add(2);
        nums.add(4);
        /*
            filter(...) 过滤出来满足条件的数据
            比如:想要所有的奇数
         */
        List<Integer> c1 = nums.stream().filter(n -> n % 2 != 0).collect(Collectors.toList());
        System.out.println(c1);
        /*
            distinct()  去重      lambda表达式,可以理解为一个没有名字的方法
         */
        nums.stream().distinct().forEach(e -> System.out.print(e + " "));
    }
}

class Class1{
    public static<T> void m1(T a){
        System.out.println(a);
    }
}

3)sorted、limit与skip

sorted():根据元素的自然顺序对流进行排序。

sorted(Comparator  c) : 根据自己定义的比较器排序,自定义比较规则

limit(int size): 截取流中前size个元素

skip(int size): 忽略流中前size个元素

测试代码如下: 

import java.util.ArrayList;
import java.util.List;

public class _02sorted_limit_skip {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(3);
        nums.add(2);
        nums.add(5);
        nums.add(4);
        nums.add(1);
        //sorted():默认升序排序
        // sorted(Comparator c) 自定义比较规则
        nums.stream().sorted((n,m)->m-n).forEach(System.out::println);
        //limit(Long size):表示截取流中的前size个元素
        nums.stream().limit(2).sorted((a,b)->a-b).forEach(s->System.out.print(s + " "));
        System.out.println("-------------------------");
        /*
            skip(long size):
         */
        nums.stream().filter(e->e!=2).sorted().skip(2).forEach(System.out::println);
    }
}

 4)map与mapToInt(mapToLong、mapToDouble)

map(....):   将元素映射成另外一种类型 将上述元素映射成字符串类型

mapToInt(......):   将元素映射成intStream

mapToLong(......):   将元素映射成longStream

mapToDouble(......):   将元素映射成doubleStream

测试代码如下: 

package com.se.day08.dStreammMid;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class _03Map_mapToInt {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        nums.add(3);
        nums.add(2);
        nums.add(5);
        nums.add(4);
        nums.add(1);

        /*
            map(....): 将元素映射成另外一种类型
            将上述元素映射成字符串类型
         */
        List<String> collect = nums.stream().map(e -> "" + e * 10).collect(Collectors.toList());
        System.out.println(collect);
//        System.out.println(nums.stream().);


        /*
            mapToInt(......): 将元素映射成intStream
            mapToLong(......): 将元素映射成longStream
            mapToDouble(......): 将元素映射成doubleStream

         */

        int sum = nums.stream().mapToInt(e -> 1).sum();
        System.out.println("元素个数:"+sum);

    }
}

 4)flatMap

flatMap: 扁平式映射。 一般针对的都是集合元素仍然是一个集合。

         普通的集合[1,2,3,4,5]  集合元素式集合的:[[1,2,10],[1,3,4],[2,4,5]]

扁平式映射: 就是将元素式集合的这种特殊集合,转成普通的集合。

         如将集合 [[1,2,10],[1,3,4],[2,4,5]]  转成: [1,2,10,1,3,4,2,4,5]。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class _04flatMap {
    public static void main(String[] args) {
        //集合out的元素依然是集合。
        List<List<Integer>> out = new ArrayList<>();
        out.add(Arrays.asList(1,2,3));
        out.add(Arrays.asList(4,5,6));
        out.add(Arrays.asList(7,8,9));

        //flatMap(....)传入一个lambda表达式: e ->e.stream()   压平了。
        long count = out.stream().flatMap(e -> e.stream()).count();
        System.out.println(count);
    }
}

 2.5 综合案例

需求 : 一个集合中存储了了若干个Student对象 , 要求查询出以下结果 :
1. 所有及格的学生信息
2. 所有及格的学生姓名
3. 所有学生的平均成绩
4. 班级的前3名(按照成绩)
5. 班级的3-10名(按照成绩)
6. 所有不不及格的学生平均成绩
7. 将及格的学生 , 按照成绩降序输出所有信息
8. 班级学生的总分

代码演示:

Student类

public class Student implements Comparable<Student>{
    private String name;
    private double score;

    public Student(){}
    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }
    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int compareTo(Student o) {
        return 0;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}'+'\n';
    }
}

 功能实现:

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.stream.Stream;

public class H1 {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("张三",99));
        students.add(new Student("李四",89));
        students.add(new Student("王五",59));
        students.add(new Student("赵六",65));
        students.add(new Student("宋茜",79));
        students.add(new Student("齐大",100));
        students.add(new Student("乔二",93));
        students.add(new Student("陈三",66));
        students.add(new Student("忘忧",69));
        students.add(new Student("星辰",94));
        students.add(new Student("大海",13));
        students.add(new Student("八六",86));
        students.add(new Student("热气",50));
        System.out.println(students);
        Stream<Student> studentStream = students.stream().filter(e -> e.getScore() >= 60);
        //所有及格的学生信息
        System.out.println("-------------------------------------------------------");
        System.out.println("1.所有及格的学生信息:");
        studentStream.forEach(System.out::print);
        System.out.println("-------------------------------------------------------");
        System.out.println("2.所有及格学生的姓名: ");
        Stream<Student> studentStream1 = students.stream().filter(e -> e.getScore() >= 60);
        studentStream1.forEach(e -> System.out.println(e.getName()));

        System.out.println("-------------------------------------------------------");
        OptionalDouble average = students.stream().mapToDouble(Student::getScore).average();
        System.out.println("3.所有学生的平均成绩为:"+average.getAsDouble());
        System.out.println("-------------------------------------------------------");
        System.out.println("4.前三名:");
        students.stream().sorted((a,b)-> (int) (b.getScore()-a.getScore())).limit(3).forEach(System.out::print);
        System.out.println("--------------------------------------------------------");
        System.out.println("5.第3到10名");
        students.stream().sorted((a,b)->(int)(b.getScore()-a.getScore())).skip(2).limit(7).forEach(System.out::print);
        System.out.println("--------------------------------------------------------");
        OptionalDouble average1 = students.stream().filter(a -> a.getScore() < 60).mapToDouble(e -> e.getScore()).average();
        System.out.println("6.不及格的平均成绩为:"+average1.getAsDouble());
        System.out.println("--------------------------------------------------------");
        System.out.println("7.所有及格的学生按成绩降序输出所有信息");
        students.stream().filter(e -> e.getScore() >= 60).sorted((a,b)->(int) (b.getScore()-a.getScore())).forEach(System.out::print);
        System.out.println("--------------------------------------------------------");
        System.out.println("8.班级总分:");
        double sum = students.stream().mapToDouble(Student::getScore).sum();
        System.out.println(sum+"分");
    }
}

结果展示:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值