目录
Stream介绍
Stream是Java8中处理集合的关键抽象概念。
Stream API对集合数据进行操作,类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之它提供了一种高效且易于使用处理数据的方式。
流(Stream)到底是什么
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算
注意:
Stream不会自己存储元素。
Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream操作的步骤
创建Stream:一个数据源,获取一个流。
中间操作:对数据源的数据进行处理。
终止操作:执行中间操作链并产生结果。
创建流Stream的四种方式
方式一: 通过Collection系列集合提供的Stream()或parallelStream()
List<String > list = new ArrayList<>();
Stream<String> stream1 = list.stream();
方式二:通过Arrays中的静态方法Stream()获取数组流
Employee[] emps = new Employee[20];
Stream<Employee> stream2 = Arrays.stream(emps);
方式三: 通过Stream类中的静态方法of()
Stream<String>stream3 = Stream.of("aa","bb");
方式四: 创建无限流:迭代/生成(迭代:一个数加三,限制数量10个 生成:生成不限量随机数)
Stream<Integer> stream4 = Stream.iterate(0,(x)->x+3);
stream4.limit(10).forEach(System.out::println);
// 创建无限流,生成
Stream.generate(()->Math.random())
.forEach(System.out::println);
Stream中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线触碰终止操作,否则中间操作不会做任何处理,而在终止操作时一次性全部处理,称为“惰性求值”。
中间操作主要涉及方面
筛选与切片 、映射、排序。
筛选与切片
主要方法:
filter - 接收lambda,从流中排除某些元素。
limit - 截断流,使其元素不超过给定的数量。
skip(n)- 跳过元素,返回一个扔掉了前n个元素的流,若流中的元素不足n个,则返回一个空流,与limit(n)互补。
distinct - 筛选,通过流所生成的元素hashCode和equals()去除重复元素。
示例1:
创建Employee(属性 name age salary)
public interface ShaiXuanYuQiePian {
public static void main(String[] args) {
List<Employee> list = Arrays.asList(
new Employee("张三",18,9999),
new Employee("赵四",58,8888),
new Employee("王五",26,7777),
new Employee("赵六",36,5555),
new Employee("田七",17,33333),
new Employee("田七",17,33333 )
);
// 内部迭代:迭代器由Stream API完成
// 排除<35岁的
Stream s = list.stream()
.filter((e)->e.getAge()>35);
// 终止操作
s.forEach(System.out::println);
System.out.println("-------------------------------");
// 外部迭代:按顺序迭代每一个元素
Iterator<Employee> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("------------------------------");
// 排除工资<5000的,并且只显示2个人的信息
list.stream()
.filter((e)->e.getSalary()>5000)
.limit(2)
.forEach(System.out::println);
System.out.println("------------------------------");
// 排除工资<5000的并跳过前两个人的信息
list.stream()
.filter((e)->e.getSalary()>5000)
.skip(2)
.forEach(System.out::println);
System.out.println("------------------------------");
// 排除工资<5000的并跳过前两个人的信息,并除去重复信息
list.stream()
.filter((e)->e.getSalary()>5000)
.skip(2)
.distinct()
.forEach(System.out::println);
}
}
映射
主要方法
map - 接收lambda,将元素转换成其他形式或提取信息,接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
flatMap - 接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流。
示例2:
public class YingShe {
public static void main(String[] args) {
List<Employee> list = Arrays.asList(
new Employee("张三",18,9999),
new Employee("赵四",58,8888),
new Employee("王五",26,7777),
new Employee("赵六",36,5555),
new Employee("田七",17,33333)
);
List<String> list1 = Arrays.asList("aaa","bbb","ccc","ddd","eee");
// 将流中灭个元素的小写都换为大写
list1.stream()
.map((str)->str.toUpperCase(Locale.ROOT))
.forEach(System.out::println);
System.out.println("--------------------------");
//获取所有姓名
list.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("-------------------------");
// 获取流中字符串的每一元素
//map返回一个流1Stream,流中保存的事流2Stream<Character>{流1{流2a,a,a},{流2b,b,b}}
Stream<Stream<Character>> stream =list1.stream()
.map(YingShe::filterCharacter);
stream.forEach((sm)->sm.forEach(System.out::print));
System.out.println("------------------------");
// 方法二:代替上述map{a,a,a,b,b,b}
Stream<Character> sm = list1.stream()
.flatMap(YingShe::filterCharacter);
sm.forEach(System.out::print);
}
// Character:对单个字符进行操作 Stream<character>将字符串提取出来转换成流
public static Stream<Character> filterCharacter(String str){
List<Character>list = new ArrayList<>();
// toCharArray() 方法将字符串转换为字符数组
for(Character ch: str.toCharArray()){
list.add(ch);
}
return list.stream();
}
}
排序
主要方法
sorted - 自然排序
sorted(Comparator com)-定制排序
示例3:
如果年龄相等就按照姓名排,否则按照年龄排
public class Paixu {
public static void main(String[] args) {
List<Employee> list = Arrays.asList(
new Employee("张三",18,9999),
new Employee("赵四",58,8888),
new Employee("王五",26,7777),
new Employee("赵六",36,5555),
new Employee("田七",17,33333),
new Employee("田",17,33333 )
);
list.stream()
.sorted((e1,e2)->{
if(e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return new Integer (-e1.getAge()).compareTo(new Integer(e2.getAge())) ;
}
}).forEach(System.out::println);
}
}
Stream终止操作
从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer
查找与匹配
主要方法:
* allMatch-检查是否匹配所有元素 * anyMatch-检查是否pip一个元素 * noneMatch-检查是否没有匹配所有元素 * findFirst-返回第一个元素 * findAny-返回当前流中的任意元素 * count-返回流中元素的总个数 * max-返回流中最大值 * min-返回流中最小值
示例四:
private Employees.Status Status;
public Employees(String name, int age, int salary, Status Status) {
this.name = name;
this.age = age;
this.salary = salary;
this.Status = Status;
}
public void setStatus(Employees.Status status) {
Status = status;
}
public Employees.Status getStatus() {
return Status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", Status=" + Status +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public Employees() {
}
public enum Status{
FREE,
BUSY,
VOCATION;
}
}
public class Test {
public static void main(String[] args) {
List<Employees> employee = Arrays.asList(
new Employees("张三",18,9999, Employees.Status.FREE),
new Employees("李四",58,8888, Employees.Status.BUSY),
new Employees("王五",26,5555, Employees.Status.VOCATION),
new Employees("赵六",36,6666, Employees.Status.FREE),
new Employees("田七",12,3333, Employees.Status.BUSY)
);
// 判断Employees.Status.BUSY状态是否所有元素
boolean b1 = employee.stream()
.allMatch(e->e.getStatus().equals(Employees.Status.BUSY));
System.out.println(b1);
//判断Employees.Status.BUSY是否与集合中一个元素匹配
boolean b2 = employee.stream()
.anyMatch(e->e.getStatus().equals(Employees.Status.BUSY));
System.out.println(b2);
// 判断Employees.Status.BUSY 是否没有匹配集合的所有元素
boolean b3= employee.stream()
.noneMatch(e->e.getStatus().equals(Employees.Status.BUSY));
System.out.println(b3);
//Optional是容器类,将对象封装到这个容器里,避免空指针异常
// findFirst-返回第一个元素,如果第一个值有可能为空值就将对象封装到Optional
Optional<Employees> op = employee.stream()
.sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
.findFirst();
System.out.println(op.get());
// filter 方法用于通过设置的条件过滤出元素
// 返回当前流中的任意元素
Optional<Employees> op2 =employee.stream()
.filter((e)->e.getStatus().equals(Employees.Status.FREE))
.findAny();
System.out.println(op2.get());
// 返回流中元素的总个数
Long count = employee.stream()
.count();
System.out.println(count);
// 返回最大/小值
Optional<Employees> op3 = employee.stream()
.max((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()));
System.out.println(op3);
Optional<Integer> op4 = employee.stream()
.map(Employees::getSalary)
.min(Integer::compare);
System.out.println(op4);
}
}
归约
reduce(T identity(起始值),BinayOperator(二元运算))/reduce(BinayOperator)-可以将流中元素反复结合起来
案例5:
public static void main(String[] args) {
List<Employees1> employee = Arrays.asList(
new Employees1("张三",18,9999, Employees1.Status.FREE),
new Employees1("李四",58,8888, Employees1.Status.BUSY),
new Employees1("王五",26,5555, Employees1.Status.VOCATION),
new Employees1("赵六",36,6666, Employees1.Status.FREE),
new Employees1("田七",12,3333, Employees1.Status.BUSY)
);
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//数组个元素相加
Integer sum = list.stream()
.reduce(0,(x,y)->x+y);
System.out.println(sum);
System.out.println("------------------------- ");
// 上边函数不可能为空所以用Integer,下边函数可能为空所以返回Optional
// map和reduce的链接通常称为map-reduce模式,如大数据搜索热词
//薪资相加
Optional<Integer> op = employee.stream()
.map(Employees1::getSalary)
.reduce(Integer::sum);
System.out.println(op);
System.out.println("--------------------");
}
收集
收集:collect(Collector); collector叫做收集器是一个接口,作用是你想按照哪一个收集器的方式收集 collector是一个接口,意味着要传他的实例必须传他的对应实现类collectors
示例6:收集常用的方法代码中均有标注
public static void main(String[] args){
List<String> list1= employee.stream()
.map(Employees1::getName)
// Collectors.toList() 将流中的所有元素收集到 List 中
.collect(Collectors.toList());
System.out.println(list1);
System.out.println("----------------");
// 将流中所有有元素收集到set中
Set<String> set = employee.stream()
.map(Employees1::getName)
.collect(Collectors.toSet());
System.out.println(set);
System.out.println("--------------------------");
/*
Collectors toCollection(Supplier<C> collectionFactory)
方法用于使用 Collector 创建一个 Collection。
它返回一个收集器,它将输入元素按照传递的顺序累积到一个新的集合中。
比如你需要返回一个特殊集合时,或者逆向返回任何类型集合
*/
HashSet<String> hs =employee.stream()
.map(Employees1::getName)
.collect(Collectors.toCollection(HashSet::new ));
hs.forEach(System.out::println);
// 人数总数
Long count = employee.stream()
.collect(Collectors.counting());
System.out.println(count);
// 平均值
Double avg = employee.stream()
.collect(Collectors.averagingDouble(Employees1::getSalary));
System.out.println(avg);
// 工资总和
int sum1 = employee.stream()
.collect(Collectors.summingInt(Employees1::getSalary));
System.out.println(sum1);
// 最大值
Optional<Employees1> op3 = employee.stream()
.collect(Collectors.maxBy((e1,e2)->Integer.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op3);
// 最小值
Optional<Employees1>op4 = employee.stream()
.collect(Collectors.minBy((e1,e2)->Integer.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op4);
System.out.println("-------------------");
分组
Map<Employees1.Status,List<Employees1>> map = employee.stream()
.collect(Collectors.groupingBy(Employees1::getStatus));
System.out.println(map);
System.out.println("-------------------");
//多及分组
Map<Employees1.Status,Map<String,List<Employees1>>> map1 = employee.stream()
.collect(Collectors.groupingBy(Employees1::getStatus,Collectors.groupingBy((e)->
{
if(((Employees1)e).getAge()<=35){
return "青年";
}else{
return"老年";
}
}
))) ;
System.out.println(map1);
// 分区:分TRUE和FALSE的两个区,满足条件的一个区,不满足条件的一个区、
Map<Boolean,List<Employees1>> map2 = employee.stream()
.collect(Collectors.partitioningBy((e)->e.getSalary()>8000));
System.out.println(map2);
System.out.println("------------------");
// 收集
String str = employee.stream()
.map(Employees1::getName)
.collect(Collectors.joining(","));
System.out.println(str);
}
}