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;
}
}
}