Day_26 【Java基础】Stream API 与 Optional类【附源码】

一、Stream API

1.为什么要使用Stream API?
实际开发中,需要操作的数据大都来自于mysql或Oracle等关系数据库,还有的数据库如Redis、MongDB,对于这些非关系数据库的操作就需要Java层面处理(Stream API)。
2.Stream和Collection集合的区别?
Collectio是一种静态的数据内存结构,面向内存,存储在内存中;而Stream是有关计算的,面向CPU,通过CPU计算处理。
3.什么是Stream API?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,Stream讲的是计算!
注意:
① stream自己不会存储元素;
② Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream;
③ Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4.Stream操作的三步骤
(1)创建Stream
一个数据源(如:集合、数组),获取一个流
(2)中间操作
一个中间操作链(多个操作),对数据源的数据进行处理
(3)终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再被使用
Day_26 【Java基础】Stream API 与 Optional类【附源码】
(1)创建Stream的四种方式:

@Test
public void test01(){
    //创建Stream方式一:使用集合
    List<String> list = Arrays.asList("北京", "上海", "广州", "深圳");
    //default Stream<E> stream():返回一个顺序流
    Stream<String> stream = list.stream();
    //default Stream<E> parallelStream():返回一个并行流
    Stream<String> stringStream = list.parallelStream();
    //创建Stream方式二:使用数组
    String[] arr = new String[]{"Java","Python","PHP","C++","GO"};
    //调用Arrays的public static <T> Stream<T> stream(T[] array):返回一个流
    Stream<String> stream1 = Arrays.stream(arr);
    //创建Stream方式三:使用Stream的of()
    Stream<Integer> stream2 = Stream.of(12, 5, 8, 46);
    //创建stream方式四:创建无限流(了解)
    //迭代(遍历前十个偶数)
    //public static<T> Stream<T> iterate(final T seed,final Unaryoperator<T> f)
    Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
    //生成
    //public static<T>Stream<T> generate(Supplier<T> s)
    Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

(2)Stream的中间操作

//User类只是一个JavaBean
public class User {
    private int id;
    private String name;
    private int age;
    private double salary;
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    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 double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
    public User() { }
    public User(int id, String name, int age, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                "name='" + name +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                age == user.age &&
                Double.compare(user.salary, salary) == 0 &&
                Objects.equals(name, user.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(id, name, age, salary);
    }
    public static List<User> getUsers(){
        ArrayList<User> users = new ArrayList<>();
        users.add(new User(1001,"马云",36,600.05));
        users.add(new User(1002,"乔布斯",34,800.23));
        users.add(new User(1003,"马化腾",31,599.35));
        users.add(new User(1004,"雷军",25,450.21));
        users.add(new User(1005,"任正非",46,756.35));
        users.add(new User(1006,"比尔盖茨",50,960.87));
        users.add(new User(1007,"李彦宏",26,630.31));
        users.add(new User(1008,"扎克伯格",18,265.45));
        users.add(new User(1008,"扎克伯格",18,265.45));
        return users;
    }
}

① 筛选与切片

//1.筛选与切片
@Test
public void test01(){
    List<User> users = User.getUsers();
    Stream<User> stream = users.stream();
    //1.查询User的salary大于700的User信息
    //filter(Predicate p)——接收Lambda:从流中过滤某些元素
    stream.filter(u -> u.getSalary() > 700).forEach(System.out::println);
    System.out.println("--------------------------------------------------");
    //2.limit(n)——截断流:使其输出的元素不超过指定数量
    users.stream().limit(2).forEach(System.out::println);
    System.out.println("--------------------------------------------------");
    //3.skip(n)——跳过元素:返回一跳过前面的n个元素的流,若不足,返回一个空流
    users.stream().skip(5).forEach(System.out::println);
    System.out.println("--------------------------------------------------");
    //4.distinct()——去重:通过流生成的hashcode()和equals()去除重复元素
    users.stream().distinct().forEach(System.out::println);
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】
② 映射


//2.映射
@Test
public void test02(){
    //map(Function f):接受一个函数作为参数,将函数转换成其他提取信息,该函数会被应用于每个元素上,并将其映射成一个新的元素
    List<String> list = Arrays.asList("GG", "BB", "MM", "DD");
    //将集合list中的元素转换为小写并遍历输出
    list.stream().map(str -> str.toLowerCase()).forEach(System.out::println);
    //练习:查找User中名字大于三位的User
    List<User> users = User.getUsers();
    Stream<String> nameStream = users.stream().map(User::getName);
    nameStream.filter(name -> name.length()>3).forEach(System.out::println);
    //flatMap(Function f):接收一个函数作为参数,将流中的每个值转换为另一个流,然后把所有的流连接成一个流
    Stream<Character> characterStream = list.stream().flatMap(StreamTest::stringToStream);
    characterStream.forEach(System.out::println);
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> stringToStream(String str){
    ArrayList<Character> list = new ArrayList<>();
    for(Character ch : str.toCharArray()){
        list.add(ch);
    }
    return list.stream();
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】
③ 排序
Day_26 【Java基础】Stream API 与 Optional类【附源码】

//3.排序
@Test
public void test03(){
    //数组排序
    List<Integer> list = Arrays.asList(18, 25, 36, 22, 10,-2);
    list.stream().sorted().forEach(System.out::println);
//        //抛异常java.lang.ClassCastException,原因User未实现Comparable接口
//        List<User> users = User.getUsers();
//        users.stream().sorted().forEach(System.out::println);//自然排序
    //对象排序
    List<User> users = User.getUsers();
    users.stream().sorted((u1, u2) -> {
        int ageValue = Integer.compare(u1.getAge(), u2.getAge());//age正序
        if(ageValue!=0){
            return ageValue;
        }else{
            return Double.compare(u1.getSalary(),u2.getSalary());//salary正序
        }
    }).forEach(System.out::println);
    System.out.println();
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】
(2)Stream的终止操作
① 匹配与查找

//① 匹配与查找
@Test
public void test01(){
    List<User> users = User.getUsers();
    //allMatch(Predicate p)——检查是否匹配所有元素。练习:是否所有的员工的年龄都大于20
    boolean b = users.stream().allMatch(u -> u.getAge() > 20);
    System.out.println(b);//false
    System.out.println("--------------------------------------------------");
    //anyMatch(Predicate p)——检查是否至少匹配一个元素。练习:是否存在员工的工资大于500
    boolean b1 = users.stream().anyMatch(u -> u.getSalary() > 500);
    System.out.println(b1);
    System.out.println("--------------------------------------------------");
    //noneMatch(Predicate p)——检查是否没有匹配的元素。练习:是否存在员工姓"雷”
    boolean b2 = users.stream().noneMatch(u -> u.getName().startsWith("任"));
    System.out.println(b2);
    System.out.println("--------------------------------------------------");
    //findFirst——返回第一个元素
    Optional<User> first = users.stream().findFirst();
    System.out.println(first);
    System.out.println("--------------------------------------------------");
    //findAny——返回当前流中的任意元素
    Optional<User> any = users.stream().findAny();
    System.out.println(any);
    System.out.println("--------------------------------------------------");
    //count——返回流中元素的总个数
    long count = users.stream().count();
    System.out.println(count);
    System.out.println("--------------------------------------------------");
    //max (Comparator c)——返回流中最大值 练习:返回最高的工资
    Stream<Double> doubleStream = users.stream().map(u -> u.getSalary());
    Optional<Double> max = doubleStream.max(Double::compare);
    System.out.println(max);
    System.out.println("--------------------------------------------------");
    //min( Comparator c)——返回流中最小值 练习:返回最低工资的员工
    Optional<User> minUser = users.stream().min((u1, u2) -> Double.compare(u1.getSalary(), u2.getSalary()));
    System.out.println(minUser);
    System.out.println("--------------------------------------------------");
    //forEach(Consumer c)——内部迭代
    users.stream().forEach(System.out::println);
    System.out.println("--------------------------------------------------");
//        //使用集合的遍历操作
//        users.forEach(System.out::println);
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】
② 归约

//② 归约
@Test
public void test02(){
    //reduce(T identity,Binaryoperator)——可以将流中元素反复结合起来,得到一个值,返回一个T。练习1:计算1-10的自然数的和
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer sum = list.stream().reduce(0, Integer::sum);//第一个参数是初始值
    System.out.println(sum);
    //reduce(Binaryoperator)——可以将流中元素反复结合起来,得到一个值。返回Optional<T> 练习2:计算公司所有员工工资的总和
    List<User> users = User.getUsers();
    Stream<Double> doubleStream = users.stream().map(User::getSalary);
//        Optional<Double> sumSalary = doubleStream.reduce(Double::sum);//Double中的public static double sum(double a, double b)
    Optional<Double> sumSalary = doubleStream.reduce((d1, d2) -> d1 + d2);
    System.out.println(sumSalary);
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】
③ 收集

//③ 收集
@Test
public void test03(){
    //collect(collector c)-将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中的元素做汇总的方法
    //练习1:查找工资大于700的员工,结果返回为一个List或Set
    List<User> users = User.getUsers();
    List<User> userList = users.stream().filter(u -> u.getSalary() > 700).collect(Collectors.toList());
    userList.forEach(System.out::println);
    System.out.println("------------------------------------------------");
    Set<User> userSet = users.stream().filter(u -> u.getSalary() > 700).collect(Collectors.toSet());
    userSet.forEach(System.out::println);
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】

二、Optional类

Optional< T >类(java.util.Optional)是一个容器类, 为了避免避免空指针异常而出现的。

Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Day_26 【Java基础】Stream API 与 Optional类【附源码】

public class Boy {
    private Girl girl;
    public Boy() {
    }
    public Boy(Girl girl) {
        this.girl = girl;
    }
    public Girl getGirl() {
        return girl;
    }
    public void setGirl(Girl girl) {
        this.girl = girl;
    }
    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }
}
class Girl {
    private String name;
    public Girl() {
    }
    public Girl(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Test
public void test01(){
    Girl girl = new Girl();
    //Optional.of(T t) :创建一个Optional实例,t必须非空
    //Optional.empty() : 创建一个空的Optional实例
    Optional<Girl> girl1 = Optional.of(girl);
    System.out.println(girl1);
    //Optional.ofNullable(T t): t可以为null
    girl = null;
    Optional<Girl> girlOptional = Optional.ofNullable(girl);
    System.out.println(girlOptional);
    //orElse(T t1):如果单前的optional内部封装的t是非空的,则返回内部的t.如果内部的是空的,则返回orElse()方法中的参数t1.
    Girl girl2 = girlOptional.orElse(new Girl("赵敏"));
    System.out.println(girl2);
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】

@Test
public void test02(){
    Boy boy = new Boy();//情况一:boy为空,girl为空
    boy = null;
    String girl = getGirl(boy);
    System.out.println(girl);
    Boy boy1 = new Boy();//情况二:boy非空,girl为空
    String girl1 = getGirl(boy1);
    System.out.println(girl1);
    Boy boy2 = new Boy(new Girl("赵敏"));
    String girl2 = getGirl(boy2);
    System.out.println(girl2);
}
public String getGirl(Boy boy){
    Optional<Boy> optionalBoy = Optional.ofNullable(boy);
    //此时的boy一定非空
    Boy boy1 = optionalBoy.orElse(new Boy(new Girl("周芷若")));
    Girl girl = boy1.getGirl();
    Optional<Girl> optionalGirl = Optional.ofNullable(girl);
    //此时的girl一定非空
    Girl girl1 = optionalGirl.orElse(new Girl("小昭"));
    return girl1.getName();
}

Day_26 【Java基础】Stream API 与 Optional类【附源码】

上一篇:[Leetcode 703]流中第K个最大元素Kth Largest Element in a Stream优先队列


下一篇:ijkplayer 代码走读之 read_thread 线程中 av_read_frame() 数据流读取过程详解