Java8 Stream API学习

Java8 Stream API使用示例

Stream是什么?

Java8中的Stream,也叫流,不过不同于IO流,它是对集合操作的一个增强API,个人理解,1、它使用内部迭代操作集合;2、它提供了类似数据库中count、avg等聚合操作,学习过程中留个记录,话不多说,上代码。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {
	public static void main(String[] args) {
		/**
		 * 创建流
		 * 1、Collection等通过stream()方法、Arrays中得静态方法stream()获取数组流
		 * 2、Stream.of(),Stream.iterate()、Stream.generate()无限流
		 */
		//初始化数据
		List<Student> list = new ArrayList<>();
		list.add(new Student(5, "张三", 22,"语文", 85));
		list.add(new Student(1, "李四", 23,"数学", 86));
		list.add(new Student(4, "麻子", 21,"语文", 82));
		list.add(new Student(6, "麻子", 21,"英语", 98));
		list.add(new Student(2, "张三", 22,"数学", 99));
		list.add(new Student(7, "李四", 23,"语文", 90));
		//list.add(new Student(8, "李四", 23,"语文", 90)); //测试去重的时候可以加上这条记录
		
		/*
		 * 1.1、filter 过滤数据,留下入参返回true的数据
		 * 需求:查询分数大于90的人
		 */
		List<Student> collect = list.stream().filter(s -> s.getScore()>90).collect(Collectors.toList());
		System.out.println("1.1、filter 查询分数大于90的人:"+collect);
		
		/*
		 * 1.2、filter 过滤数据,留下入参返回true的数据
		 * 需求:查询语文分数大于等于90的人
		 */
		List<Student> c2 = list.stream()
				.filter(s -> {
			       if(s.getSubject().equals("语文") && s.getScore()>=90){
			    	   return true;
			       }else{
			    	   return false;
			       }
			    }).collect(Collectors.toList());
		System.out.println("1.2、filter 查询语文分数大于等于90的人:"+c2);
		
		/*
		 *这里输出用了lambda的方法引用 
		 *概念:对于一个lambda表达式只是调用了一个方法时,可以用方法引用的方式简化lambda表达式
		 *方法引用的标准形式是:类名::方法名。(注意:只需要写方法名,不需要写括号)
			有以下四种形式的方法引用:
			类型	示例
			引用静态方法	ContainingClass::staticMethodName
			引用某个对象的实例方法	containingObject::instanceMethodName
			引用某个类型的任意对象的实例方法	ContainingType::methodName
			引用构造方法	ClassName::new
		 *
		 */
		list.stream()
				.filter(s -> {
			       if(s.getSubject().equals("语文") && s.getScore()>=90){
			    	   return true;
			       }else{
			    	   return false;
			       }
			    }).forEach(System.out::println); //方法引用
		
		/*
		 * 2.1、map 转换,可以将原对象转换成另一个对象流
		 * 典型需求:得到id列表
		 */
		List<Integer> idList = list.stream().map(Student::getId).collect(Collectors.toList());
		System.out.println("2.1、map 由List<Student>转换后得到List<Integer>id列表:"+idList);
		
		/*
		 * 2.2、mapToDouble 转换,可以将原对象流转换成Double流
		 * 典型需求:求张三的平均分
		 */
		OptionalDouble average = list.stream()
				.filter(s -> s.getName().equals("张三")) //保留张三的记录
				.mapToDouble(Student::getScore) //将分数转成一个mapToDouble流
				.average(); //求平均分
		DoubleSummaryStatistics summary = list.stream()
				.filter(s -> s.getName().equals("张三")) //保留张三的记录
				.mapToDouble(Student::getScore) //将分数转成一个mapToDouble流
				.summaryStatistics();
		System.out.println("2、mapToDouble 求张三的平均分:" + (average.isPresent()?average.getAsDouble():average.orElse(0)));
		System.out.println("2、summaryStatistics 张三分数统计:" + "总分:"+summary.getSum()+",最高分:"+summary.getMax()+",最低分:"+summary.getMin()+",共几科:"+summary.getCount()+",平均分:"+summary.getAverage());
		
		/*
		 * 3、distinct 去重,根据对象的hashCode和equals方法去重
		 * 典型需求:列表去重
		 */
		List<Student> distinctList = list.stream().distinct().collect(Collectors.toList());
		System.out.println("3、distinct 去重后列表:"+distinctList);
		
		/*
		 * 4、sort 排序,可以自定义排序规则
		 * 需求:先根据姓名升序,再根据科目升序,在再根据分数降序
		 */
		List<Student> sortedList = list.stream().sorted(Comparator.comparing(Student::getName) //姓名升序
				//.thenComparing(Student::getSubject) //科目升序
				.thenComparing(Student::getScore).reversed()) //分数降序
		.collect(Collectors.toList());
		System.out.println("4、sort 先根据姓名升序,再根据科目升序,在再根据分数降序:"+sortedList);
		
		/*
		 * 5、peek 什么都不干,一般用于调试,输出元素啥的
		 * 按照Java团队的说法,peek()方法存在的主要目的是用调试,通过peek()方法可以看到流中的数据经过每个处理点时的状态
		 * 需求:过滤长度大于3的字符串,转成大写
		 */
		Stream.of("one", "two", "three", "four")
        .filter(e -> e.length() > 3) //长度大于3的,得到 "three", "four"
        .peek(e -> System.out.println("Filtered value: " + e))
        .map(String::toUpperCase) // 转成大写
        .peek(e -> System.out.println("Mapped value: " + e))
        .collect(Collectors.toList());
		
		/*
		 * 6、limit 截取前N条数据
		 * 需求:截取前3条数据
		 */
		List<Student> limitList = list.stream().limit(3)
		.collect(Collectors.toList());
		System.out.println("6、limit 截取前3条数据:"+limitList);
		
		/*
		 * 6、skip 跳过N条数据
		 * 需求:跳过1条数据
		 */
		List<Student> skipList = list.stream().skip(1)
				.collect(Collectors.toList());
		System.out.println("7、skip 跳过1条数据:"+skipList);
		
		/*
		 * 7.1、reduce 归约(把值合成一个)  使用只有一个入参的情况
		 * Optional<T> reduce(BinaryOperator<T> accumulator); 
		 * 需求:求和
		 */
		Optional<Integer> accResult = Stream.of(1, 2, 3, 4)
				.reduce((acc, item) -> { //第一个参数是统计值,第一次执行是第一个元素;第二个参数是流元素,第一次是第二个元素
					System.out.println("acc : "  + acc); //统计结果,第一次执行是第一个元素
					acc += item;
					System.out.println("item: " + item); //流里面的元素,第一次是第二个元素
					System.out.println("acc+ : "  + acc); //统计结果
					System.out.println("--------");
					return acc;
				});
		System.out.println("7.1、reduce 归约  使用只有一个入参的情况   统计结果: " + accResult.get());
		System.out.println("--------");
		
		/*
		 * 7.2、reduce 归约(把值合成一个)  使用有两个入参的情况,第一个入参是统计初始值,第二个是累加器
		 * T reduce(T identity, BinaryOperator<T> accumulator); 
		 * param :identity 是返回结果
		 * param:accumulator 累加器
		 * 需求:求和
		 */
		Integer accResult2 = Stream.of(1, 2, 3, 4)
				.reduce(0,(acc, item) -> { //第一个参数0是统计结果初始值;第二个参数是累加器,跟上面一样
					System.out.println("acc2 : "  + acc); //统计结果,第一次执行是初始值0
					acc += item;
					System.out.println("item2: " + item); //流里面的元素,第一次是第1个元素
					System.out.println("acc2+ : "  + acc); //统计结果
					System.out.println("--------");
					return acc;
				});
		System.out.println("7.2、reduce 归约  使用有两个入参的情况  统计结果2: " + accResult2);
		System.out.println("--------");
		
		/*
		 * 8.1、Collectors.groupingBy
		 * 需求:根据姓名分组
		 * return Map<String, List<Student>>, key姓名,value:该姓名对应的对象列表
		 */
		Map<String, List<Student>> groupList = list.stream()
				.collect(Collectors.groupingBy(Student::getName));
		System.out.println("8.1、Collectors.groupingBy 根据姓名分组:"+groupList);
		
		/*
		 * 8.2、Collectors.groupingBy
		 * 需求:根据姓名分组,并统计每个分组有多少个元素(count)
		 * return Map<String, Long>, key:姓名,value:该组有多少个元素
		 * 例:{李四=2, 张三=2, 麻子=2}
		 */
		Map<String, Long> groupCount = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.counting()));
		System.out.println("8.2、Collectors.groupingBy 根据姓名分组,并统计每个分组有多少个(count):"+groupCount);
		
		/*
		 * 8.3、Collectors.groupingBy
		 * 需求:根据姓名分组,并统计每个分组各科平均分
		 * return Map<String, Double>, key:姓名,value:平均分
		 * 例:{李四=88.0, 张三=92.0, 麻子=90.0}
		 */
		Map<String, Double> groupAvg = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.averagingDouble(Student::getScore)));
		System.out.println("8.3、Collectors.groupingBy 根据姓名分组,并统计每个分组各科平均分:"+groupAvg);
		
		/*
		 * 8.4、Collectors.groupingBy
		 * 需求:根据姓名分组,并统计每个分组总分
		 * return Map<String, Double>, key:姓名,value:总分
		 * 例:{李四=176.0, 张三=184.0, 麻子=180.0}
		 */
		Map<String, Double> groupSum = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.summingDouble(Student::getScore)));
		System.out.println("8.4、Collectors.groupingBy 根据姓名分组,并统计每个分组总分:"+groupSum);
		
		/*
		 * 8.5、Collectors.groupingBy 多字段分组
		 * 需求:根据姓名,学科分组
		 * return Map<String, Map<String, List<Student>>>, key:姓名,value:map(key:学科,value:列表)
		 * 例:{李四={数学=[Student [name=李四, subject=数学, score=86.0]], 语文=[Student [name=李四, subject=语文, score=90.0]]}, 张三={数学=[Student [name=张三, subject=数学, score=99.0]], 语文=[Student [name=张三, subject=语文, score=85.0]]}, 麻子={语文=[Student [name=麻子, subject=语文, score=82.0]], 英语=[Student [name=麻子, subject=英语, score=98.0]]}}
		 */
		Map<String, Map<String, List<Student>>> groups = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.groupingBy(Student::getSubject)));
		System.out.println("8.5、Collectors.groupingBy 多字段分组-根据姓名,学科分组:"+groups);
	}
	
	private static class Student{
		private int id; //id
		private String name; //姓名
		private int age; //年龄
		private String subject; //学科
		private float score; //分数
		public Student(int id,String name,int age,String subject,float score){
			this.id=id;
			this.name=name;
			this.age=age;
			this.subject=subject;
			this.score=score;
		}
		public int getId() {
			return id;
		}
		@SuppressWarnings("unused")
		public void setId(int id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		@SuppressWarnings("unused")
		public void setName(String name) {
			this.name = name;
		}
		@SuppressWarnings("unused")
		public int getAge() {
			return age;
		}
		@SuppressWarnings("unused")
		public void setAge(int age) {
			this.age = age;
		}
		public float getScore() {
			return score;
		}
		@SuppressWarnings("unused")
		public void setScore(float score) {
			this.score = score;
		}
		@Override
		public String toString() {
			return "Student [name=" + name + ", subject=" + subject + ", score=" + score + "]";
		}
		public String getSubject() {
			return subject;
		}
		@SuppressWarnings("unused")
		public void setSubject(String subject) {
			this.subject = subject;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			result = prime * result + ((subject == null) ? 0 : subject.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Student other = (Student) obj;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.equals(other.name))
				return false;
			if (subject == null) {
				if (other.subject != null)
					return false;
			} else if (!subject.equals(other.subject))
				return false;
			return true;
		}
	}
}


  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值