console.log('点个关注再走吧🍺');|

Tod4

园龄:2年11个月粉丝:21关注:0

JDK版本特性(二)StreamAPI

Stream API


1 概述

  • Stream是java8中处理集合的关键抽象概念
  • 它可以指定对集合进行的操作,比如执行肥非常复杂的查找、过滤和映射等操作
  • 还可以使用Steam API来进行并行操作

2 Steam实例化

2.1 集合创建

​ 实现自接口collection.stream()

@Test
public void genByCollection() {
var list = new ArrayList<Integer>();
Stream<Integer> stream = list.stream();
}
2.2 数组创建

​ 来自Arrays工具类的stream方法

@Test
public void genByArray() {
var arr = new int[]{1, 2, 3};
IntStream stream = Arrays.stream(arr);
Stream<String> stream2 = Arrays.stream(new String[]{"1", "2"});
var es = new Employee[3];
es[0] = new Employee();
es[1] = new Employee();
es[2] = new Employee();
Stream<Employee> stream1 = Arrays.stream(es);
}
2.3 Stream创建
@Test
public void genByStream() {
Stream<Integer> integerStream = Stream.of(4, 5, 6);
}
2.4 无限流
@Test
public void test() {
// 输出前十个偶数
Stream.iterate(0, t -> t + 2)
// 中间操作
.limit(10)
// 终止操作
.forEach(System.out::println);
// 生成5个随机数
// 提供一个supplier接口
Stream.generate(Math::random)
// 中间操作
.limit(5)
// 终止操作
.forEach(System.out::println);
}

3 Stream中间操作

3.1 常见中间流操作
  • 过滤流 filter:

  • 截断流 limit:

  • 跳跃流 skip:

  • 筛选流 distinct:去除重复元素,根据对象的HashCode

    流经过终止操作后就会被关闭,不能够再回到中间操作

/**
* 中间操作测试
*/
@Test
public void test1() {
var list = EmployeeData.getEmployees();
// 过滤流
list.stream()
.filter(e -> e.getAge() % 2 == 1)
.forEach(System.out::println);
// 截断流
list.stream()
.limit(4)
.forEach(System.out::println);
// 跳跃流
list.stream()
.skip(3)
.forEach(System.out::println);
list.add(new Employee("1", 1));
list.add(new Employee("1", 1));
list.add(new Employee("1", 1));
// 筛选流
list.stream().distinct()
.forEach(System.out::println);
}
3.2 映射
  • map(Function f):接收一个函数作为参数,将流中的每个值都经过该函数处理后转化为一个流,然后嵌套到最外层的流里面

    var list = Arrays.asList("aa", "bb", "cc");
    //aa
    //bb
    //cc
    Stream<Stream<Character>> characterStream =
    list.stream().map(StreamMapTest::fromStringToStream);
  • flatMap(Function f):接收一个函数作为参数,将流中的每个值都转化为一个流,然后把所有的流连接成一个流,类似于对流的一个扁平(flat)处理

    characterStream.forEach(s -> {
    s.forEach(System.out::print);
    System.out.println();
    });
    Stream<Character> flatStream
    = list.stream().flatMap(StreamMapTest::fromStringToStream);
    // aabbcc
    flatStream.forEach(System.out::print);
  • mapToDouble(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Double流

  • mapToInt(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Int流

  • mapToLong(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Long流

4 终止操作

4.1 match & find 匹配与查找
  • allMatch:true | false

  • anyMatch:true | false

  • noneMatch:true | false

  • count:返回流的元素的个数

  • findFirst:返回Optional(防止空指针)

  • findAny:返回Optional(防止空指针)

  • max:返回Optional(防止空指针)

  • min:返回Optional(防止空指针)

    @Test
    public void test() {
    var list = EmployeeData.getEmployees();
    var res1 = list.stream().allMatch(e -> e.getAge() > 18);
    // false
    System.out.println(res1);
    var res2 = list.stream().anyMatch(e -> e.getAge() > 18);
    // false
    System.out.println(res2);
    // true
    var res3 = list.stream().noneMatch(e -> e.getAge() > 18);
    System.out.println(res3);
    var res4 = list.stream().count();
    // 7
    System.out.println(res4);
    Optional<Employee> first = list.stream().findFirst();
    // Optional[Employee(name=0001, age=1)]
    System.out.println(first);
    Optional<Employee> any = list.parallelStream().findAny();
    // Optional[Employee(name=0005, age=5)]
    System.out.println(any);
    // Optional[Employee(name=0007, age=7)]
    Optional<Employee> max = list.stream().max(Comparator.comparingInt(Employee::getAge));
    System.out.println(max);
    // Optional[Employee(name=0001, age=1)]
    Optional<Employee> min = list.stream().min(Comparator.comparingInt(Employee::getAge));
    System.out.println(min);
    }
4.2 reduce 规约
  • reduce(T identity, BinaryOperator accumulator)可以将流中的元素反复结合起来,得到一个值,并返回计算的值加上初始值identity

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer reduce
    = list.stream().reduce(10, Integer::sum);
    // 65
    System.out.println(reduce);
  • eg:获取全部员工年龄加和

    var list2 = EmployeeData.getEmployees();
    var sum = list2.stream()
    .map(Employee::getAge)
    .reduce(0, Integer::sum);
    System.out.println(sum);
4.3 收集
  • collect(Collector c):将流转化为其他形式,接收一个Collector接口实现,用于给Stream中元素做汇总的方法

  • Collector接口中的方法决定了如何对流执行收集的操作(如收集到List、Set、Map等)

    @Test
    public void test2() {
    // 查找年龄大于5的员工,并返回为一个list或者set
    var list = EmployeeData.getEmployees();
    var resList = list.stream().filter(e -> e.getAge() > 5)
    .collect(Collectors.toList());
    System.out.println(resList);
    var resSet = list.stream().filter(e -> e.getAge() > 5)
    .collect(Collectors.toSet());
    System.out.println(resSet);
    }
  • Collectors的相关方法有:

    • toList():把流中的元素收集到list
    • toSet():把流中的元素收集到Set
    • toCollection():
    • counting()::
    • summingInt():
    • averagingInt():
    • summarizingInt():返回值为IntSummaryStatistics,收集流中Integer属性的统计值,如平均值

5 Optional类

​ Optional通过检查空值的方式防止代码污染,避免空指针异常

5.1 Optional的创建
  • Optional.of(T t):创建一个Optional实例,t必须非空,否则会报空指针

  • Optional.empty():创建一个空Optional

  • Optional.ofNullable(T t):t可以为空,如果为空返回的是一个value为null的Optional.Empty常量

    Girl girl = new Girl();
    girl = null;
    // nullPointerException
    var optionalGirl
    = Optional.of(girl);
  • Optional.orElse(T t):为空的时候指定返回值,避免了空指针问题

    public String getGirlName(Boy boy) {
    var optionalBoy = Optional.ofNullable(boy);
    // boy1一定非空
    var boy1 = optionalBoy.orElse(new Boy(new Girl("girl1")));
    var girl = boy1.getGirl();
    var optionalGirl = Optional.ofNullable(girl);
    var girl1 = optionalGirl.orElse(new Girl("girl2"));
    return girl1.getName();
    }
  • Optional.get():获取Optional封装的值,如果为空则会抛出异常

  • boolean isPresnt():判断是否包含对象

  • void ifPresent(Consumer<? extends T> consumer):如果有值,就将该值作为参数就执行Consumer接口的实现代码

  • T orElseGet(Supplier<? extends T> other):如果没有值,则执行Supplier接口返回的值作为该值返回

  • T orElseThrow(Supplier<? extends X> eceptionSupplier):如果存在值则将值返回,否则抛出supplier接口得到的异常

4 动态代理

  • 代理模式的原理

    使用一个代理对象将对象包装起来,然后使用该代理对象包装原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上

  • 静态代理举例:

    thread就是一个代理对象,t则是被代理对象,当执行start方法的时候,实际上就是执行的MyThread被代理类的run方法

    public class MyThread implements Runnable{
    @Override
    public void run() {
    }
    @Test
    public void test() {
    MyThread t = new MyThread();
    Thread thread = new Thread(t);
    thread.start();
    }
    }
  • 静态代理的缺点:

    • 每个代理类只能为一个接口服务,程序开发必然会产生过多的代理
    • 代理类和目标类(被代理类)都是在编译期间确定下来,不利于程序的扩展
    • 最好能够通过一个代理类实现全部的代理功能——动态代理
  • 动态代理指的是客户通过代理类来调用其他对象方法,并且在程序运行时根据需要动态创建目标类的代理对象

  • 动态代理需要解决的问题:

    • 如何根据加载到内存的被代理类,动态地创建一个代理类及其对象(通过Proxy.newProxyInstance)
    • 当通过代理类的对象调用方法a的时候,如何动态地去调用被代理的同名方法a
posted @   Tod4  阅读(33)  评论(0编辑  收藏  举报
   
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起