Hello Java8 快速上手第二篇

4.Stream流

4.1 创建Stream流

4.1.1 有限流: 根据创建字段确定大小有限的流
  • Arrays.stream(Object[] objs),传入数组/对象组
  • Stream<T>.of(T… values),传入泛型为T的可变参数,注意当传入集合时,并不会对集合进行拆解操作
  • collection.stream(),colleciton可以直接调用接口方法获取流
  • 在《Java8 实战》中还提到了通过文件创建流的方式, 本文暂略
    //1.Arrays.stream(Object[] objs)
    User[] users = {new User(1, "test1"),new User(2, "test2")};
    Arrays.stream(users).forEach(item -> System.out.println(item));
     
     //2.Stream.of(T...value)
     Stream.of(new User(3, "test3"),new User(4, 
"test4")).forEach(item -> System.out.println(item));  //输出每个user对象
     Stream.<u>of</u>(list).forEach(item -> System.out.println(item));  //易错,此处传入集合时输出的是list对象
     
     //3.collection.stream()
     list.stream().forEach(item -> System.out.println(item));    //输出list中每个user对象
4.1.2 无限流:大小无限的流
  • Stream.iterate(final T seed, final UnaryOperator<T> f)
  • Stream.generate(Supplier<T> s)

无限流的创建与使用暂略;

4.2 流的使用

(1)流的中间操作与终端操作表

中间操作: 也叫连接操作,类似于new StringBuilder().append(“a”).append(“b”).append(“c”)这样的方式,其原理为方法的返回类型与对象类型相同;
终端操作: 即方法的返回类型与对象类型不一致时,不可再连续调用的操作

Hello Java8 快速上手第二篇

(2)常用操作

//准备数据
List<Student> students = new ArrayList<>();
//学生对象数据结构: Student{id, name, age, Score{ chinese, math, english}}
students.add(new Student(1001, "tom", 18, new Score(61, 90, 95)));
students.add(new Student(1002, "jack", 20, new Score(59, 60, 71)));
students.add(new Student(1003, "jenny", 18, new Score(82, 75, 77)));
students.add(new Student(1004, "cat", 22, new Score(40, 45, 80)));

//1.for-each操作
//旧写法
for(Student s : students){
    System.out.println(s);
}
//java8写法
students.stream().forEach(System.out::println);

//2.filter筛选
//filter会将遍历流,将返回值为true的对象保存,返回为false的过滤掉
//获取成绩全部合格的学生
List<Student> passStudents = students.stream()
    .filter(item -> item.score.chinese >= 60 && item.score.math >= 60 && item.score.math >= 60)
    .collect(Collectors.toList());
System.out.println(passStudents);
          
//3.distinct去重
Integer[] ins = {1,1,2,3,4,4,5,6,6,6};
Arrays.stream(ins).distinct().forEach(item -> System.out.print(item + " "));
System.out.println();   //1,2,3,4,5,6

//4.limit截断
//获取前两位英语成绩及格的学生
List<Student> engPassStudents = students.stream().filter(item -> item.score.english >= 60).limit(2).collect(Collectors.toList());
System.out.println(engPassStudents);    //学生1,2

//5.skip跳过
//跳过前两位英语成绩及格的学生,显示剩余英语及格的全部学生
List<Student> engPassSkip2Student = students.stream().filter(item -> item.score.english >= 60).skip(2).collect(Collectors.toList());
System.out.println(engPassSkip2Student);    //学生3,4

//6.map对对象操作,可更改返回值类型
//将学生集合转化为成绩集合
List<Score> scores = students.stream().map(item -> item.score).collect(Collectors.toList());
System.out.println(scores);     //{[<chinese:61.0-math:90.0-english95.0>, ...]}
System.out.println(scores.size());  //4

 //7.flatMap扁平化流,扁平化指将二维->一维
 //此处将3个String类型的对象数组 -> 转为了14个String类型的对象的集合
String[] ss = {"hello", "java", "8 1th"};
List<String> collect = Arrays.stream(ss).map(item -> item.split("")).flatMap(item -> Arrays.stream(item)).collect(Collectors.toList());
List<String[]> collect2 = Arrays.stream(ss).map(item -> item.split("")).collect(Collectors.toList());
System.out.println(collect.size());     //14
System.out.println(collect2.size());    //3
String[] strings = collect2.get(0);
System.out.println(strings[0]);     //h

//8.anyMatch,allMatch,noneMatch
//任意学生年龄小于20即为true
boolean anyMatch = students.stream().anyMatch(item -> item.age < 20);
System.out.println(anyMatch);   //true
//全部学生年龄小于20才为true
boolean allMatch = students.stream().allMatch(item -> item.age < 20);  
System.out.println(allMatch);   //false
boolean allMatch2 = students.stream().allMatch(item -> item.age < 40);
System.out.println(allMatch2);      //true
//没有学生年龄小于20才为true
boolean noneMatch = students.stream().noneMatch(item -> item.age < 20);
System.out.println(noneMatch);      //false
boolean noneMatch2 = students.stream().noneMatch(item -> item.age < 16);
System.out.println(noneMatch2);     //true

//9.并行流,findAny,findFirst
//获取一名年龄小于22岁的学生
Optional<Student> findFirst = students.stream().filter(item -> item.age < 22).findFirst();
Optional<Student> findAny = students.stream().filter(item -> item.age < 22).findAny();
System.out.println(findFirst);      //id-1
System.out.println(findAny);      //id-1

//并行流获取一名年龄小于22岁的学生
Optional<Student> findFirst2 = students.parallelStream().filter(item -> item.age < 22).findFirst();
Optional<Student> findAny2 = students.parallelStream().filter(item -> item.age < 22).findAny();
System.out.println(findFirst2);     //id-1
System.out.println(findAny2);     //id-1 or id-2 or id-3, 效率最高

//10.规约,排序,最大值,最小值
Integer[] integers = {1,3,2,4,5};
Integer reduce = Arrays.asList(integers).stream().reduce(0,Integer::sum);
System.out.println(reduce);

List<Integer> arrays = Arrays.asList(integers).stream().sorted().collect(Collectors.toList());
System.out.println(arrays);     //1,2,3,4,5
Optional<Integer> max = Arrays.asList(integers).stream().reduce(Integer::max);
Optional<Integer> min = Arrays.asList(integers).stream().reduce(Integer::min);
System.out.println("max---" + max + "min---" + min);    //5,1,

4.3 关于流和集合

此处待更新

4.4 流的使用问题

此处待更新


5.Collector收集器

5.1 Stream使用Collector收集数据

(1)Collector简介

Stream接口中collect()方法的声明如下:

collect(Collector<? super T, A, R> collector);

因此之前章节用到的 list.stream().collect(Collectors.toList()) 返回成一个List接口的集合是通过传入Collector接口的实现的方式转化成了一个List接口的集合;

toList方法的源码如下:

public static <T> Collector<T, ?, List<T>> toList() {

    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, 
List::add, (left, right) -> { left.addAll(right); return left; },CH_ID);
}

Collectors是一个java8已提供的类,其中提供了一些常用功能的静态方法(返回Collector的实现),如Collectors.toList()等;

(2)常用方法
//1. 转为list, set, map
List<Student> <u>list</u> = students.stream().collect(Collectors.toList());
Set<Student> <u>set</u> = students.stream().collect(Collectors.toSet());
Map<Integer, Score> map = students.stream().collect(Collectors.toMap(Student::getId,Student::getScore));

//2.count,sum,min,avg,max
//班级语文成绩 总数,总分,最小值,平均值,最大值
DoubleSummaryStatistics sum = students.stream().collect(Collectors.summarizingDouble(item -> item.getScore().chinese));
System.out.println(sum);
//DoubleSummaryStatistics{count=4, sum=242.000000, min=40.000000, average=60.500000, max=82.000000}
//或Collectors.counting(), Collectors.summingDouble(), Collectors.averagingDouble(), Collectors.minBy(), Collectors.maxBy(),

//3.分组,根据不同的age分组
Map<Integer, List<Student>> <u>map1</u> = students.stream().collect(Collectors.groupingBy(Student::getAge));
System.out.println(map);

 //4.分区,原方法为按boolean分区, 因此只能分为两个片区
Map<Boolean, List<Student>> <u>map2</u> =students.stream().collect(Collectors.partitioningBy(item -> item.age < 18));

5.2 自定义Collector接口

此处待更新

附: Stream流源码
public interface Stream<T> extends BaseStream<T, Stream<T>> {
 
	Stream<T> filter(Predicate<? super T> predicate);
 
	<R> Stream<R> map(Function<? super T, ? extends R> mapper);
 
	IntStream mapToInt(ToIntFunction<? super T> mapper);
 
	LongStream mapToLong(ToLongFunction<? super T> mapper);
 
	DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
 
	<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
 
	IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
 
	LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
 
	DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
 
	Stream<T> distinct();
 
	Stream<T> sorted();
 
	Stream<T> sorted(Comparator<? super T> comparator);
 
	Stream<T> peek(Consumer<? super T> action);
 
	Stream<T> limit(long maxSize);
 
	Stream<T> skip(long n);
 
	void forEach(Consumer<? super T> action);
 
	void forEachOrdered(Consumer<? super T> action);
 
	Object[] toArray();
 
	<A> A[] toArray(IntFunction<A[]> generator);
 
	T reduce(T identity, BinaryOperator<T> accumulator);
 
	Optional<T> reduce(BinaryOperator<T> accumulator);
 
	<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
 
	<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);
 
	Optional<T> min(Comparator<? super T> comparator);
 
	Optional<T> max(Comparator<? super T> comparator);
 
	long count();
 
	boolean anyMatch(Predicate<? super T> predicate);
 
	boolean allMatch(Predicate<? super T> predicate);
 
	boolean noneMatch(Predicate<? super T> predicate);
 
	Optional<T> findFirst();
 
	Optional<T> findAny();
 
	public static <T> Builder<T> builder() {
		return new Streams.StreamBuilderImpl<>();
	}
 
	public static <T> Stream<T> empty() {
		return StreamSupport.stream(Spliterators.<T> emptySpliterator(), false);
	}
 
	public static <T> Stream<T> of(T t) {
		return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
	}
 
	@SafeVarargs
	@SuppressWarnings("varargs") // Creating a stream from an array is safe
	public static <T> Stream<T> of(T... values) {
		return Arrays.stream(values);
	}
 
	public static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
		Objects.requireNonNull(f);
		final Iterator<T> iterator = new Iterator<T>() {
			@SuppressWarnings("unchecked")
			T t = (T) Streams.NONE;
 
			@Override
			public boolean hasNext() {
				return true;
			}
 
			@Override
			public T next() {
				return t = (t == Streams.NONE) ? seed : f.apply(t);
			}
		};
		return StreamSupport.stream(
				Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
	}
 
	public static <T> Stream<T> generate(Supplier<T> s) {
		Objects.requireNonNull(s);
		return StreamSupport.stream(new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s),
				false);
	}
 
	public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
		Objects.requireNonNull(a);
		Objects.requireNonNull(b);
 
		@SuppressWarnings("unchecked")
		Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>((Spliterator<T>) a.spliterator(),
				(Spliterator<T>) b.spliterator());
		Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
		return stream.onClose(Streams.composedClose(a, b));
	}
 
	public interface Builder<T> extends Consumer<T> {
		@Override
		void accept(T t);
 
		default Builder<T> add(T t) {
			accept(t);
			return this;
		}
 
		Stream<T> build();
 
	}
}

本篇为Java8中核心部分Stream流的使用介绍, 本文为日常工作学习笔记与总结, 如有不正指出劳烦指出!
更多相关知识, 以及实际运用中遇到的问题会及时更新, 更多源码实现,java8思想及底层逻辑可看《Java8 实战》等权威资料!
感谢阅读!