Stream

函数式接口

    java8提供了很多新的特性,Lambda表达式,函数式接口,Optional,新的日期类api。在聊Stream之前我们先来说下什么是函数式接口
    Lambda表达式很多人都在使用了,而函数式接口则是为了支持Lambda表达式,Java8提供了很多内置的函数式接口,如Runnable,Comparator等是从原有的API升级来的,而有些是Java8新增的,如Consumer等。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

    类上有注解@FunctionalInterface就可以认为这是一个函数式接口,可以用在Lambda表达式中。Lambda表达式极大的简化了我们的编程

// jdk1.8之前
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("yes");
    }
}).start();
// jdk1.8及以后
new Thread(() -> System.out.println("yes")).start();

    为方便使用lambda表达式,java8提供了一些内置的函数式接口

函数式接口方法用途
Consumer 消费型接口void accept(T t)输入参数为T,没有返回
Supplier 供给型接口T get()返回R
Function<T, R> 函数型接口R apply(T t)输入参数为T,返回为R
Predicate 判断型接口boolean test(T t)对象是否满足条件,true为满足,false为不满足

函数式接口的使用:

@Test
public void test1() {
    consumeTask(10, (m) -> System.out.println(m));// 10
}
public void consumeTask(int num, Consumer<Integer> consumer) {
    consumer.accept(num);
}

@Test
public void test2() {
    System.out.println(strHandler("aaa", (str) -> str.toUpperCase()));// AAA
}
public String strHandler(String str, Function<String, String> function) {
    return function.apply(str);
}

其他内置接口:

函数式接口方法
BiFunction<T, U, R>R apply(T t, U u)
BiConsumer<T, U>void accept(T t, U u)
ToIntFunctionint applyAsInt(T value)
IntFunctionR apply(int value)

Stream

Stream介绍

java8的时候出现了stream,用来简化对集合的操作,stream的设计基于函数式编程和lambda表达式
     Stream操作分为如下三个步骤
    1、创建stream操作分为如下三个步骤
    2、中间操作,对数据进行处理
    3、终止操作,执行中间操作,并产生结果,一般返回void或一个非流的结果
需要注意的是,如果不执行终止操作,那么中间操作不会执行

创建Stream

//1.Collection集合的stream() 或者 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
//2.调用Arrays.stream(T[] array) 静态方法
Integer[] array = {1, 2, 3, 4, 5};
Stream<Integer> streamArray = Arrays.stream(array);
//3.调用Stream.of(T... values)静态方法    常用方法
Stream<String> streamStream = Stream.of("a", "b", "c", "d", "e");
//4.调用Stream.iterate(final T seed, final UnaryOperator<T> f),创建无限流
// (x) -> x + 2 为函数式接口,传入x返回x+2,0为最开始的值
Stream<Integer> integerStream = Stream.iterate(0, (x) -> x + 2);
// 一直输出 0 2 4 6 8 10 12
integerStream.forEach(System.out::println);
//5.调用Stream.generate() 创建无限流
Stream<Integer> generateStream = Stream.generate(() -> 10);
//一直输出10 可以用Random等类随机生成测试
generateStream.forEach(System.out::println);

中间操作

筛选和切片
    filter 从流中排除某些元素
    limit 使元素不超过指定数量
    skip 跳过前n个元素,如果流中元素不超过n个,则返回一个空流
    distinct 通过hashCode() 和 equals() 去除重复元素

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
integerList.stream().filter(x -> x % 2 == 1).forEach(System.out::println);//输出 1、3、5
integerList.stream().skip(2).forEach(System.out::println);//输出 3、4、5

filter方法和forEach方法的定义 函数式接口

Stream<T> filter(Predicate<? super T> predicate);
void forEach(Consuer<? super T> action);

很多方法的入参其实就是一个函数式接口
映射
    map 接收一个函数作为参数,该函数被应用到每个元素上,并将其映射成一个新的元素
    flatMap 接受一个函数作为参数,将流中的每一个值都转换成另一个流,然后将所有流连接成一个流

<R> Stream<R> map(Function<? super T, ? extends T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

map方法的入参和返回值可以为任意值
flatMap方法的入参为任意值,返回值必须为Stream

List<String> stringList = Arrays.asList("abcd", "efgh");
// [Ljava.lang.String;@7b3300e5 [Ljava.lang.String;@2e5c649
stringList.stream().map(x -> x.split("")).forEach(System.out::println);
// a b c d e f g h
stringList.stream().flatMap(x -> Arrays.stream(x.split(""))).forEach(System.out::println);

x.spit("")后为数组,所以第一个输出的为数组的地址
第二个x.split("")后为数组,然后将数组转为多个流,将多个流合并后输出
排序
sorted() 自然排序,通过Comparable接口定义的规则来排序
sorted(Comparator) 定制排序,通过Comparator接口定义的规则来排序

List<String> sortList = Arrays.asList("b", "a", "c");
// a b c
sortList.stream().sorted().forEach(System.out::println);
// c b a
sortList.stream().sorted((x, y) -> y.compareTo(x)).forEach(System.out::println);

终止操作

查找与匹配
    allMatch 是否匹配所有元素
    anyMatch 是否至少匹配一个元素
    noneMatch 是否没有匹配所有元素
    findFirst 返回第一个元素
    findAny 返回当前流中的任意元素
    count 返回当前流中元素总个数
    max 返回流中最大值
    min 返回流中最小值

List<Integer> integersList = Arrays.asList(1, 2, 3, 4);
// false
// 当list都为1时才会返回true
System.out.println(integersList.stream().allMatch(num -> num.equals(1)));
// true
System.out.println(integersList.stream().anyMatch(num -> num.equals(1)));
// 4
System.out.println(integersList.stream().max((x, y) -> x.compareTo(y)).get());

归约
reduce 归约,将流中元素反复结合起来得到一个值

List<Integer> asList = Arrays.asList(1, 2, 3, 4);
int sum = asList.stream().reduce(0, (x, y) -> x + y);
// 10
// 初始值为0,执行过程为
// x = 0 y = 1
// x = 1 y = 2
// x = 3 y = 4 ...
// 10
// 10
System.out.println(sum);

收集
用collect方法进行收集 方法定义

 <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator,
                BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
@Data
@AllArgsConstructor
 public class Student {
    private String name;
    private int age;
 }
List<Student> studentList = Arrays.asList(new Student("张三", 30),
        new Student("李四", 20),
        new Student("王五", 20));

List<String> nameList = studentList.stream().map(Student::getName).collect(Collectors.toList());
// [张三, 李四, 王五]
System.out.println(nameList);

Set<Integer> ageSet = studentList.stream().map(Student::getAge).collect(Collectors.toSet());
// [20, 30]
System.out.println(ageSet);

LinkedHashSet<Integer> linkedHashSet =
        studentList.stream().map(Student::getAge).collect(Collectors.toCollection(LinkedHashSet::new));
// [30, 20]
System.out.println(linkedHashSet);
// 总数
long count = studentList.stream().collect(Collectors.counting());
// 3
System.out.println(count);

// 平均值
double ageAvg = studentList.stream().collect(Collectors.averagingDouble(Student::getAge));
// 23.3
System.out.println(ageAvg);

// 总和
int totalAge = studentList.stream().collect(Collectors.summingInt(Student::getAge));
// 70
System.out.println(totalAge);

// 最大值
Optional<Student> student = studentList.stream().collect(Collectors.maxBy((x, y) -> x.getAge() - y.getAge()));
// Student(name=张三, age=30)
System.out.println(student.get());

// 按照年龄分组
// 还可以多级分组,按照年龄分组后,再按照其他条件分组,不再演示
Map<Integer, List<Student>> listMap = studentList.stream().collect(Collectors.groupingBy(Student::getAge));
// {20=[StreamDemo.Student(name=李四, age=20), StreamDemo.Student(name=王五, age=20)], 30=[StreamDemo.Student(name=张三, age=30)]}
System.out.println(listMap);

枚举值参数校验
项目中有很多单选项需要定义相关的枚举值,前端传入后需要校验这些值是否在枚举范围内

public enum MSG_TYPE {
		IMAGE((byte) 0, "图片"),
		TEXT((byte) 1, "文本");
		public final byte value;
		public final String name;
		
		MSG_TYPE(byte value, String name) {
		    this.value = value;
		    this.name = name;
		}
}
// 模拟前端传入的参数为1
boolean isExist = Arrays.stream(MSG_TYPE.values()).anyMatch(v -> v.value == 1);
// true
System.out.println(isExist);
isExist = Arrays.stream(MSG_TYPE.values()).anyMatch(v -> v.value == 5);
// false
System.out.println(isExist);

调用远程服务前存对应关系
根据学生姓名获取学生的其他信息
    1.先存学生姓名 -> 学生的映射关系为nameMap
    2.通过学生姓名调用其他服务批量获取学生信息
    3.从nameMap中根据其他服务返回的学生姓名拿到Student,然后填充信息到Student

List<Student> studentList = Lists.newArrayList();
for (int i = 0; i < 3; i++) {
      Student student = Student.builder().name("学生" + i).age(i).build();
      studentList.add(student);
  }
// {学生0=Student(name=学生0, age=0), 学生2=Student(name=学生2, age=2), 学生1=Student(name=学生1, age=1)}
Map<String, Student> studentMap = studentList.stream().collect(Collectors.toMap(Student::getName, student -> student));
System.out.println(studentMap);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值