直接上代码(所有案例):
public class StreamMethod extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
}
/**
* 以下是Stream流的常用方法!
**/
/**
* limit()方法,获取Stream流中指定的数量的数据
* */
@Test
void limitTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.limit(4).forEach(System.out::println);
}
/**
* skip()方法 ,跳过Stream流中指定的数量的数据
* */
@Test
void skipTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.skip(4).forEach(System.out::println);
}
/**
* filter()方法 ,根据条件过滤数据
* */
@Test
void filterTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.filter(s -> s>5).forEach(System.out::println); //过滤Stream中大于5的数据
}
/**
* foreach()方法,遍历Stream流
* */
@Test
void foreachTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.forEach(System.out::println);
}
/**
* count()方法,计算Stream流数据的总数
* */
@Test
void countTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
long count = integerStream.count();
System.out.println(count);
}
/**
* distinct()方法,去除重复
* */
@Test
void distinctTest(){
Stream<Integer> integerStream = Stream.of(1, 2,2, 3, 4, 55, 656, 12323,55,55,656);
integerStream.distinct().forEach(System.out::println);
}
/**
* distinct()方法,去除自定义的实体类对象的重复
* 需要重写实体类的hashcode和equlse方法
* */
@Test
void distinctClassTest(){
Stream<Person> integerStream = Stream.of(
new Person("张三","18"),
new Person("李四","18"),
new Person("王五","18"),
new Person("张三","18")
);
integerStream.distinct().forEach(System.out::println);
}
/**
* sorted()方法,排序
* */
@Test
void sortedTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
/*
* sorted() 无参是正序排序
**/
//integerStream.sorted().forEach(System.out::println);
/*
* sorted() 有参,可以根据条件排序 此案例是倒序
**/
integerStream.sorted((a1,a2) -> a2-a1).forEach(System.out::println);
}
/**
* map()方法,可以把数据换类型并返回
* */
@Test
void mapTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.map(s -> s.toString())
.forEach(System.out::println);
}
/**
* match()方法 根据要求判断Stream流中数据是否符合要求
* */
@Test
void matchTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
//allMatch 如果Stream流的数据都大于55,才返回true,否则返回false
/*boolean b = integerStream.allMatch(s -> s > 55);
System.out.println(b);*/
//anyMatch 如果Stream流的数据其中有一个满足条件,就返回true
/*boolean b1 = integerStream.anyMatch(s -> s > 55);
System.out.println(b1);*/
//noneMatch 如果Stream流的数据都不满足指定条件,才返回true
boolean b2 = integerStream.noneMatch(s -> s ==999);
System.out.println(b2);
}
/**
* find()方法,找到流的首个元素
* */
@Test
void findTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
//Optional<Integer> first = integerStream.findFirst(); //找到Stream流中第一个元素
// System.out.println(first.get());
// 特地查了一下这两个方法有什么区别,findany不一定会返回首个元素
// 可以去看这个链接的解释 https://blog.csdn.net/huanghanqian/article/details/102807972
Optional<Integer> first1 = integerStream.findAny(); //找到Stream流中第一个元素,但并行流的情况下不一定返回首个
System.out.println(first1.get());
}
/**
* max()方法,排序并返回最大的值
* */
@Test
void maxTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
Optional<Integer> max = integerStream.max((a1, a2) -> a1 - a2);
System.out.println(max.get());
}
/**
* min()方法,排序并返回最小的值
**/
@Test
void minTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
Optional<Integer> min = integerStream.min((a1, a2) -> a1 - a2);
System.out.println(min.get());
}
/**
* reduce()方法 将流中数据总结起来并返回
* T reduce(T identity, BinaryOperator<T> accumulator);
* T identity:默认值 初始值
* BinaryOperator<T> accumulator : 对数据的处理方式
**/
@Test
void reduceTest(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
Integer reduce = integerStream.reduce(0, (m1, m2) -> {
System.out.println("m1: "+m1+",m2: "+m2);
return m1 + m2;
});
System.out.println("reduce:"+reduce);
System.out.println("--------------s-----------------------------");
// 也可以用作取出最大值
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4);
Integer reduce1 = integerStream1.reduce(0, (m1, m2) -> m1 > m2 ? m1 : m2);
System.out.println(reduce1);
}
/**
* map结合reduce用法
**/
@Test
void reduceAndmapTest(){
// 求出所有person对象的年龄总和
int reduce = Stream.of(
new Person("张三", "18"),
new Person("李四", "18"),
new Person("王五", "18"),
new Person("张三", "18")
).map(s -> Integer.parseInt(s.getAge()))
.reduce(0, Integer::sum); //Integer类有个sum求和方法
System.out.println("年龄之和:"+reduce);
// 求出所有person对象的年龄最大的是多少岁
int reduce1 = Stream.of(
new Person("张三", "15"),
new Person("李四", "10"),
new Person("王五", "18"),
new Person("张三", "16")
).map(s -> Integer.parseInt(s.getAge()))
.reduce(0,Math::max);
System.out.println("最大年龄是:"+reduce1);
// 取出所有person类的名字并用逗号间隔
String reduce2 = Stream.of(
new Person("张三", "15"),
new Person("李四", "10"),
new Person("王五", "18"),
new Person("马云", "16")
).map(s -> s.getName())
.reduce("", (x, y) -> x = x + y + ",");
System.out.println("姓名为:"+reduce2);
// 查询1的个数
Integer reduce3 = Stream.of(1, 2, 3, 2, 5, 1, 1, 1, 1, 1).map(s -> s == 1 ? s : 0)
.reduce(0, Integer::sum);
System.out.println("1的个数是:"+reduce3);
}
/**
* maptoInt()方法
* 在Stream流中,正常操作的整数类都是包装类
* Integer类型比int占用内存大,在Stream流中会自动装箱和拆箱
*
**/
@Test
void maptoIntTest(){
//输出大于55的数字
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 55, 656, 12323);
integerStream.filter(s -> s>55).forEach(System.out::println);
// 返回的是IntStream
// 这样的好处就是运行速度快,节省了装箱拆箱的步骤,节省了内存空间
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
IntStream intStream = integerStream1.mapToInt(s -> s.intValue());
intStream.filter(s -> s>55).forEach(System.out::println);
}
/**
* concatTest()方法,这个方法是Stream流的静态方法,上面的案例全都是Stream流的对象方法
* 将两个流合并成一个流
**/
@Test
void concatTest(){
Stream integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
Stream integerStream2 = Stream.of("1", "2", "3", "4", "55", "656","12323");
Stream concat = Stream.concat(integerStream1, integerStream2);
concat.forEach(s ->{
System.out.println(s.getClass()+":"+s);
});
}
/**
* 收集Stream流的数据到list或set
**/
@Test
void stream_To_List_Set(){
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
//将Stream收集到List集合中
// List<Integer> collect = integerStream1.collect(Collectors.toList());
// System.out.println(collect);
//将Stream收集到Set集合中
// Set<Integer> collect = integerStream1.collect(Collectors.toSet());
// System.out.println(collect);
//将Stream收集到指定的ArrayList集合中
// ArrayList<Integer> collect = integerStream1.collect(Collectors.toCollection(ArrayList::new));
// System.out.println(collect);
//将Stream收集到指定的HashSet集合中
HashSet<Integer> collect = integerStream1.collect(Collectors.toCollection(HashSet::new));
System.out.println(collect);
}
/**
* 收集Stream流的数据到数组中
**/
@Test
void stream_To_Array(){
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 55, 656, 12323);
/* Object[] objects = integerStream1.toArray();
for (Object object : objects) {
System.out.println(object);
}*/
Integer[] Integers = integerStream1.toArray(Integer[]::new);
for (Integer integer : Integers) {
System.out.println(integer);
}
}
/**
* 对流中数据进行聚合运算
**/
@Test
void streamTest(){
Stream<Person> personStream = Stream.of(
new Person("张三", "15"),
new Person("李四", "10"),
new Person("王五", "18"),
new Person("张三", "16"));
// 求出年龄最大的人
// Optional<Person> collect = personStream.collect(Collectors.maxBy((o1, o2) -> Integer.parseInt(o1.getAge()) - Integer.parseInt(o2.getAge())));
// System.out.println(collect.get());
// 求出年龄最小的人
/*Optional<Person> collect = personStream.collect(Collectors.maxBy((o1, o2) -> Integer.parseInt(o2.getAge()) - Integer.parseInt(o1.getAge())));
System.out.println(collect.get());*/
// 求出年龄平均值
// Double collect = personStream.collect(Collectors.averagingInt(value -> Integer.parseInt(value.getAge())));
// System.out.println(collect);
// 求出共有几个人
// Long collect1 = personStream.collect(Collectors.counting());
// System.out.println(collect1);
// 求出年龄总和
// Integer collect = personStream.collect(Collectors.summingInt(value -> Integer.parseInt(value.getAge())));
// System.out.println(collect);
}
/**
* 对流中数据进行分组
**/
@Test
void streamGroupTest(){
Stream<Person> personStream = Stream.of(
new Person("张三", "15"),
new Person("李四", "15"),
new Person("王五", "18"),
new Person("张三", "20"));
//对年龄进行分组
//Map<String, List<Person>> collect = personStream.collect(Collectors.groupingBy(s -> s.getAge()));
//对年龄进行分组,但是加个条件 成年和未成年
Map<String, List<Person>> collect = personStream.collect(Collectors.groupingBy(s ->
Integer.parseInt(s.getAge())<18 ? "未成年" : "成年"
));
//遍历
collect.forEach((k,v)->{
System.out.println(k+"="+v);
});
}
/**
* 对流中数据进行多级分组
**/
@Test
void streamGroupsTest(){
Stream<Person> personStream = Stream.of(
new Person("张三", "15","60"),
new Person("李四", "15","59"),
new Person("王五", "18","99"),
new Person("张三", "18","40"));
Map<String, Map<String, List<Person>>> collect = personStream.collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy(s ->
Integer.parseInt(s.getCore()) < 60 ? "不及格" : "及格"
)));
//遍历
collect.forEach((k,v)->{
System.out.println(k+"="+v);
});
}
/**
* 对流中数据进行分区
* 对数据进行判断,true为一组,false为一组 分成两个区
**/
@Test
void streamPartitioningByTest(){
Stream<Person> personStream = Stream.of(
new Person("张三", "15","60"),
new Person("李四", "15","59"),
new Person("王五", "18","99"),
new Person("张三", "18","40"));
Map<Boolean, List<Person>> collect = personStream.collect(Collectors.partitioningBy(person ->
Integer.parseInt(person.getCore()) > 60
));
//遍历
collect.forEach((k,v)->{
System.out.println(k+"="+v);
});
}
/**
* 对流中数据进行拼接
**/
@Test
void streamJoiningTest(){
Stream<Person> personStream = Stream.of(
new Person("张三", "15","60"),
new Person("李四", "15","59"),
new Person("王五", "18","99"),
new Person("张三", "18","40"));
// Collectors.joining("__","**","++") 三个参数的,第一个参数是中间拼接的字符串,第二个参数是前缀,第三个参数是后缀。得到结果:**张三__李四__王五__张三++
// String collect = personStream.map(Person::getName).collect(Collectors.joining("__","**","++"));
// Collectors.joining("__") 1个参数的,参数是中间拼接的字符串 。得到结果:张三__李四__王五__张三
// String collect = personStream.map(Person::getName).collect(Collectors.joining("__"));
// Collectors.joining() 0个参数的 。得到结果:张三李四王五张三
String collect = personStream.map(Person::getName).collect(Collectors.joining());
System.out.println(collect);
}
/**小结
* 收集Stream流中的结果
* 到集合中:Collectors.toList(),Collectors.toSet(),Collectors.toCollection()
* 到数组中:默认Object数组Collectors.toArray(), 指定类型的数组Collectors.toArray(int[]::new)
* 聚合计算:最大值Collectors.maxBy(),最小值Collectors.minBy(),统计数量Collectors.counting(),求和Collectors.summingint(),平均值Collectors.averagingInt()
* 分组:Collectors.groupingBy(),多级分组Collectors.groupingBy(Person::getAge,Collectors.groupingBy(Person::getCore))
* 分区:Collectors.partitionBy()
* 拼接:Collectors.joining()
* */
/**以上的流都是串行流,串行流是一个线程执行内容
*
*
* 并行Stream流
*
* 并行流是多个线程同时执行内容
*
* */
@Test
void BingXingStreamTest(){
List<String> list=Arrays.asList("张三","李四","王五","马六","田七");
//并行Stream流的两种获取方式:
// 第一种:直接获取并行流
//list.parallelStream().filter(s -> {
// System.out.println(Thread.currentThread());
// return true;
//}).count();;
// 第二种:将串行流转成并行流 parallel()方法
list.stream().parallel().filter(s -> {
System.out.println(Thread.currentThread());
return true;
}).count();
}
/**
* 串行流,并行流,for循环效率对比
* */
@Test
void StreamTimeTest(){
//*********************for 费时:123******************************
/*long starttimie = System.currentTimeMillis();
long time=500000000l;
long sum=0;
for (long i=1;i<=time;i++){
sum+=i;
}
long endtimie = System.currentTimeMillis();
System.out.println("费时:"+(endtimie-starttimie));*/
//*********************for 时间:123******************************
//*********************串行流 费时:209******************************
/* long starttimie = System.currentTimeMillis();
long time=500000000l;
LongStream.rangeClosed(0, time).reduce(Long::sum);
long endtimie = System.currentTimeMillis();
System.out.println("费时:"+(endtimie-starttimie));*/
//*********************串行流 费时:209******************************
//*********************并行流 费时:97******************************
long starttimie = System.currentTimeMillis();
long time=500000000l;
LongStream.rangeClosed(0, time).parallel().reduce(Long::sum);
long endtimie = System.currentTimeMillis();
System.out.println("费时:"+(endtimie-starttimie));
//*********************并行流 费时:97******************************
}
/**
* 并行流的线程安全问题
* */
@Test
void anQuanTest(){
// 不安全案例:得出结果list的size不是500, 按理说list的size应该是500,但并行流是多个线程同时运行 会造成数据安全问题
/*List<Integer> list=new ArrayList<>();
IntStream.rangeClosed(1,500).parallel().forEach(s->{
list.add(s);
});
System.out.println(list.size());*/
// 解决方案一,使用线程安全的集合
/*Vector<Integer> vector=new Vector<>();
IntStream.rangeClosed(1,500).parallel().forEach(s->{
vector.add(s);
});
System.out.println(vector.size());*/
// 解决方案二,加入同步代码块
/* List<Integer> list=new ArrayList<>();
Object ob=new Object();
IntStream.rangeClosed(1,500).parallel().forEach(s->{
synchronized (ob){
list.add(s);
}
});
System.out.println(list.size());*/
// 解决方案三,使用线程安全的list Collections.synchronizedList(list)会将一个list转成线程安全的List 也就是SynchronizedList 是List的子类
List<Integer> list=new ArrayList<>();
List<Integer> objects = Collections.synchronizedList(list);
IntStream.rangeClosed(1,500).parallel().forEach(s->{
objects.add(s);
});
System.out.println(objects.size());
// 解决方案四,调用collect的toArray boxed()方法返回一个该流元素组成的一个新流,只不过流中元素都转成了对应的包装类
/*List<Integer> collect = IntStream.rangeClosed(1, 500).parallel().boxed().collect(Collectors.toList());
System.out.println(collect.size());*/
}
/**小结
* 并行流的内部采用的是ForkJoin框架
*
* ForkJoin框架的核心和 分治法 任务窃取算法
* 分治法,将大任务拆分成小任务由多个线程去执行,最后每个小任务的结果合并起来,融合成大结果,也就是最后结果并返回
*
* 任务窃取算法,是指执行任务的多个线程中只要一个线程先执行完,就去偷其他线程的任务队列中最后一个线程,然后偷过来继续执行
* */
}
案例所需要的实体类:
import java.util.Objects;
public class Person {
String name;
String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public Person(String name, String age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}