首页 > 技术文章 > JDK 8 Stream 流 用 法

gtnotgod 2020-11-18 17:26 原文

import com.entity.Person;
import org.junit.Test;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @program: Demohander
* @description:JDK8新特性
* @author: GuoTong
* @create: 2020-11-18 10:14
**/
@SuppressWarnings("all")//正压一切警告
public class JDKStreamTest {

/*Jdk1.8中引入了stream流的概念,
这个并不同于IO中的输入和输出流,
它是Jdk中的一个类,
具体位置在:java.util.stream.Stream*/


/*关于它的操作主要分为三种:获取流、中间操作、最终操作*/

/*所谓获取流,就是将其他对象(非Stream对象)转为Stream对象。
只有两类对象可能转化为Stream对象,分别是:
数组(这个数组中的元素必须是引用类型)
集合*/

@Test
public void TestCreateStream() {
//数组获取流
Integer[] iArr = {12, 14, 15, 15, 17, 19, 22};
Stream<Integer> streamByArrInt = Stream.of(iArr);
// 数组
String[] str = "I Love You But I miss You so I miss you".split(" ");
Stream<String> streamByArrStr = Arrays.stream(str);
//集合获取流
List<String> list = Arrays.asList(str);
Stream<String> streamList = list.stream();

}

/*Stream流常用的中间操作:filter 过滤某些规则下的东西
* Stream流常用的终止操作:collect(Collectors.toList())---返回一个集合
* flatMap 可用Stream替换值,然后将多个Stream连接成一个Stream,会将之前生成Stream流的每一个元素更换为一个新的Stream对象。*/
@Test
public void TestStream01() {
//filter :
// filter方法用于通过设置的条件过滤出元素,下面的例子是过滤出长度大于3的字符串
String[] s = "I Love You But I miss You so I miss you".split(" ");
List<String> list = Arrays.asList(s);
// List流转:赛选大于3个字段的,返回一个集合
/*list.stream().filter(str -> str.length() > 3):只是流操作了,原数据并未改变*/
/*list.stream().filter(str -> str.length() > 3).collect(Collectors.toList());返回的新集合就改变了*/
List<String> collect = list.stream().filter(str -> str.length() > 3).collect(Collectors.toList());
collect.forEach(System.out::println);//还是经过流处理的集合

//map
//map元素用于映射每隔元素到对应的结果,下面的例子用map输出元素对应的平方数
Stream.of(1, 2, 3, 4, 5).map(i -> i * i).forEach(System.out::println);
System.out.println("============");
//flatMap 可用Stream替换值,然后将多个Stream连接成一个Stream,会将之前生成Stream流的每一个元素更换为一个新的Stream对象。
Stream<Integer> stream2 = Stream.of(1, 2).distinct()
.flatMap(numbers -> Stream.of(5, 6, 6, 7, 8));
//会将1,2都会替换为5,6,7,8,5,6,7,8
Object[] objects = stream2.toArray();
for (Object object : objects) {
System.out.println(object);
}
}

/*mapsorted测试*/
@Test
public void TestStream02() {
String[] str = {"1", "-12", "10", "23", "4", "7", "3"};
//map
//map元素内部遍历集合,可以对集合元素一系列操作。
List<String> list = Arrays.asList(str);
/*将集合元素转为大写(每个元素映射到大写)->降序排序->迭代输出*/
/*原始字符串的转大写,比较大小降序*/
Stream.of("a", "c", "f", "b", "w", "h", "z").map(String::toUpperCase).sorted((a, b) -> a.compareTo(b)).forEach(System.out::println);
System.out.println("====================================");
/*new Function<String, Integer>():标识类型转换:第一个范式需要转换为第二个范式的类型*/
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).sorted((x, y) -> y - x).forEach(x -> System.out.print(x + ","));/*sorted((x,y)-> y-x):内部是compareTo方法实现,采用lambda表达式*/
/*x-> System.out.print(x+",") 对比 System.out::println ,前者可以自定义输出内容,lambda表达式,后者只能原样输出*/
System.out.println("=================================");
list.stream().map(x -> x + "1").forEach(x -> System.out.print(x + ","));

}

/*mapsorted等较完整的链式编程*/
@Test
public void TestStream03() {
String[] str = {"17", "-12", "10", "23", "24", "17", "23", "15", "52", "12", "24", "14"};
List<String> list = Arrays.asList(str);
System.out.println("================集中多路=================");
/*集中多路链式编程*/
List<Integer> collect = list.stream().map(new Function<String, Integer>() {//类型转化为int
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).limit(5) //限制,只取前几个元素
.skip(1) //跳过,表示跳过前几个元素
.distinct() //去重
.sorted() //自然排序
.sorted(Integer::compareTo)//自定义排序,默认降序
.collect(Collectors.toList());//返回出去
collect.forEach(System.out::println);//打印
}

/*终止操作*/
@Test
public void TestStream04() {
//reduce:一般用于求和,第一个参数一般是结果的初始值,第二个参数操作
//静态流:Stream.of(1,2,3)
Integer reduce = Stream.of(1, 2, 3, 4, 3, 2, 5, 1, 4, 2, 5).distinct().reduce(0, (x1, x2) -> x1 + x2);
System.out.println("不重的和:" + reduce);
//第二个:collect(Collectors.toList());将流转化为XXXlistsethashset。。。。)
//stream.collect(Collectors.toCollection(HashSet::new));
String[] str = {"17", "-12", "10", "23", "24", "17", "23", "15", "52", "12", "24", "14"};
List<String> list = Arrays.asList(str);
HashSet<String> collect = list.stream().distinct().collect(Collectors.toCollection(HashSet::new));
Iterator<String> iterator = collect.iterator();//使用集合的迭代器迭代
while (iterator.hasNext()) {
String next = iterator.next();//迭代每一个元素
System.out.println(next);
}
//count方法是用来统计流中元素的个数
long count = Stream.of(1, 2, 3, 4, 3, 2, 5, 1, 4, 2, 5).distinct().count();
System.out.println("不重个数" + count);
}

/*Stream 流判空过滤*/
@Test
public void TestStream05() {
ArrayList<Person> arrayList = new ArrayList<>();
arrayList.add(new Person());
arrayList.add(null);
arrayList.add(new Person("小郭", 23));
arrayList.add(new Person("小李", 21));
arrayList.add(new Person("三少", 18));

/*过滤找出null*/
arrayList.stream().filter(Objects::isNull).forEach(person -> {
System.out.println("是空的");
});
System.out.println("=============================");
/*过滤找出不是null的,但是包含空参构造对象*/
arrayList.stream().filter(Objects::nonNull).forEach(person -> {
System.out.println(person.getAge());
System.out.println(person.getName());
});
/*arrayListnull的时候不会报空指针错误,并且还打了日志。*/
System.out.println("=============================");
arrayList = null;
Optional.ofNullable(arrayList).orElseGet(() -> {
System.out.println("personList 是空的");
return new ArrayList<>();
}).stream().filter(Objects::nonNull).forEach(person -> {
System.out.println(person.getAge());
System.out.println(person.getName());
});
}

/*Stream的匹配操作:anymatch(是否涵盖)||allMatch(全部的原始是否都涵盖)*/
@Test
public void TestStream06() {
//数据封装
ArrayList<Person> arrayList = new ArrayList<>(); arrayList.add(
new Person()); arrayList.add(
null); arrayList.add(
new Person("小郭", 23)); arrayList.add(
new Person("小李", 21)); arrayList.add(
new Person("三少", 18));
//测试涵盖
boolean anyMatch = Optional.ofNullable(arrayList).orElseGet(() -> { System.
out.println("personList 是空的");
return new ArrayList<>(); }).stream(). filter(Objects::

nonNull). filter(s -> s.getName() !=
null). anyMatch((person) -> person.getName().startsWith(
"")); String name = anyMatch ?
"涵盖--->名字以字母开头" : "不涵盖"; System.
out.println(name); System.
out.println("=====================================");
//测试是否都满足
boolean allMatch = Optional.ofNullable(arrayList).orElseGet(() -> { System.
out.println("personList 是空的");
return new ArrayList<>(); }).stream(). filter(Objects::

nonNull). filter(s -> s.getName() !=
null). allMatch(person -> person.getName().startsWith(
"")); String allName = allMatch ?
"全都--->名字以字母开头" : "不全"; System.
out.println(allName); System.
out.println("=====================================");
/*noneMatch((s) -> s.startsWith("d"));集合中是否没有元素匹配以'd'开头*/
}

/*并行 parallelStream */
@Test
public void TestStreamToDouble() {
/*回去并行流的两种方式*/
// 直接获取并行的流
ArrayList<Integer> list = new ArrayList<>(); Stream<Integer> stream01 = list.parallelStream();

// 将串行流转成并行流
ArrayList<Integer> list2 = new ArrayList<>(); Stream<Integer> stream02 = list2.stream().parallel();



/*大量数据时,并行流会比串行流更快:底层是Fork/Join框架;少量数据时,由于使用框架会损耗资源,所以建议用串行流*/
/*并行流和串行流比较*/
//顺序输出 123456789
List<Integer> numbers = Arrays.asList( 5, 6, 7, 8, 9,1, 2, 3, 4); numbers.stream().sorted().forEach(System.
out::print); System.

out.println();//换行

//并行乱序输出 比如 658974132 此输出不固定
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 3, 7, 2, 5);
//虽然写了排序,但是输出是未排序的;当然串行流不会,写了排序就会排序
nums.parallelStream().distinct().sorted((x, y) -> x - y).forEach(x->System.out.println(x+",")); System.
out.println("===================");
// count()||collect()||reduce() 是终止操作,有终止操作才会执行中间操作sorted()
List<Integer> collect = nums.parallelStream().distinct().sorted((x, y) -> x - y).collect(Collectors.toList()); collect.forEach(System.
out::println);
/*部分情况会有线程安全问题,parallelStream里面使用的外部变量,比如集合一定要使用线程安全集合,不然就会引发多线程安全问题*/
//建议使用JUC下的东西

}}

推荐阅读