1. Stream
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。==Stream 是Java8中处理集合的关键抽象概念==,它可以对==集合进行非常复杂的查找、过滤、筛选等操作.==
1.1 为什么使用stream流
当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:
一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
package demo10;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("程俊杰");
list.add("张三丰");
//1.拿到所有姓张的
List<String> newList01=new ArrayList<>();
for(String n:list){
if(n.startsWith("张")){
newList01.add(n);
}
}
//2.拿到名字长度为3个字的
List<String> newList02=new ArrayList<>();
for(String n:newList01){
if(n.length()==3){
newList02.add(n);
}
}
//3.打印这些数据
for(String s:newList02){
System.out.println(s);
}
}
}
分析:
循环遍历的弊端
这段代码中含有三个循环,每一个作用不同:
首先筛选所有姓张的人;
然后筛选名字有三个字的人;
最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。
那Stream能给我们带来怎样更加优雅的写法呢?
Stream初体验
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张三");
list.add("程俊杰");
list.add("张三丰");
//
list.stream().filter(t->t.startsWith("张")).filter(t->t.length()==3).forEach(item-> System.out.println(item));
1.2 Stream流的原理
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
1.3 步骤
(1)获取Stream流对象
(2) 中间操作---返回类型还是Stream流对象。
(3)终止操作---不在是Stream流对象
1.4 获取Stream流对象的方式
(1) 通过集合对象调用stream()
(2)通过Arrays获取stream流对象
(3)通过Stream流里面of方法
package demo11;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Test11 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
// Stream<String> stream = list.stream();
// stream.forEach(System.out::println);
// //第二种使用Arrays工具类
// String[] arr={};
// Stream<String> stream1 = Arrays.stream(arr);
//
// //第三种:Stream类
// Stream<Integer> stream2 = Stream.of(1, 2, 4, 7, 8);
//上面的流都是串行流。并行流
Stream<String> stringStream = list.parallelStream();
stringStream.forEach(System.out::println);
}
}
1.5 Stream流的api方法
举个简单的例子:
假设有一个Person类和一个Person列表,现在有两个需求:1)找到年龄大于18岁的人并输出;2)找出所有中国人的数量。
@Data
class Person {
private String name;
private Integer age;
private String country;
private char sex;
public Person(String name, Integer age, String country, char sex) {
this.name = name;
this.age = age;
this.country = country;
this.sex = sex;
}
}
public class Test {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//1. 年龄大于18 filter:过滤掉不满足条件的元素. forEach:输出元素. ---如果没有终止函数,那么中间函数的代码不会被执行。
personList.stream(). filter(item->{
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~");
return item.getAge()>18;
}).forEach(System.out::println);
//2. 找出中国人 并统计个数: count()
long count = personList.stream().filter(item
-> item.getCountry().equals("中国")).count();
System.out.println("中国人:"+count);
}
}
(2)找出年龄最大和最小
Person person = personList.stream().max(((o1, o2)
-> o1.getAge() - o2.getAge())).get();
Person person2 = personList.stream().min(((o1, o2)
-> o1.getAge() - o2.getAge())).get();
System.out.println(person);
System.out.println(person2);
(3)map-->
会把集合中的元素转化成另一种类型
personList.stream().filter(item->item.getCountry().equals("中国"))
.map(item->new P(item.getName(),item.getAge()))
.forEach(System.out::println);
public class Test03 {
public static void main(String[] args) {
// 整数数组每个元素+3
List<Integer> list = Arrays.asList(1, 17, 27, 7);
list.stream().map(item->item+3).forEach(System.out::println);
List<String> list2=Arrays.asList
("hello","world","java","spring","springmvc");
//字符串大写
list2.stream().map(String::toUpperCase).forEach(System.out::println);
}
}
(4)收集 collect
把处理过的集合搜集成新的集合。
List<Person> personList = new ArrayList<>();
personList.add(new Person("小梅",24,"中国",'F'));
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("Tom",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//把Person-年龄大于20人--里面名称----新的集合。
List<String> collect = personList.stream()
.filter(item -> item.getAge() > 20)
.map(item -> item.getName())
.collect(Collectors.toList());
System.out.println(collect);
(5)sorted排序
List<Person> collect = personList.stream()
.sorted((o1, o2) -> o1.getAge() - o2.getAge())
.collect(Collectors.toList());
System.out.println(collect);
(6) reduce规约
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
整型集合: -----请求。[1,2,3,4]=
List<Integer> list= Arrays.asList(1,2,3,5);Optional<Integer> reduce = list.stream().reduce((t1, t2) -> t1 * t2);//t1=1, t2=2 ===>2//t1=2 t2=3===>6//t1=6 t2=5====>30System.out.println(reduce.get());
(7)查询第一个findFirst
Optional<Person> first = personList.stream()
.filter(item->item.getAge()>=18&&item.getAge()<=20).findFirst();
System.out.println(first.get());
中间的操作: filter map sorted distinct() skip limit()
终止操作: forEach count() reduce() collect(Collectors.toList()) findFirst
max min
一个小例子
交易员类
public class Trader {
private String name;
private String city;
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
Transaction(交易记录)
public class Transaction {
private Trader trader; //交易员
private int year;
private int value;
public Transaction(Trader trader, int year, int value){
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader(){
return this.trader;
}
public int getYear(){
return this.year;
}
public int getValue(){
return this.value;
}
public String toString(){
return "{" + this.trader + ", " +
"year: "+this.year+", " +
"value:" + this.value +"}";
}
}
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。输出结果 (2) 交易员都在哪些不同的城市工作过? (3) 查找所有来自于剑桥的交易员,并按姓名排序。 (4) 返回所有交易员的姓名字符串,按字母顺序排序。 (5) 有没有交易员是在米兰工作的? (6) 打印生活在剑桥的交易员的所有交易额。 (7) 所有交易中,最高的交易额是多少? (8) 找到交易额最小的交易。 能使用方法引用的尽量用方法引用。
//(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。输出结果
List<Transaction> collect = transactions.stream().filter(item -> item.getYear() == 2011).sorted(Comparator.comparingInt(Transaction::getValue)).collect(Collectors.toList());
System.out.println("1、"+collect);
// (2) 交易员都在哪些不同的城市工作过?
List<String> collect1 = transactions.stream().map(item -> item.getTrader().getCity()).distinct().collect(Collectors.toList());
System.out.println("2、"+collect1);
// (3) 查找所有来自于剑桥的交易员,并按姓名排序。
List<String> cambridge1 = transactions.stream().filter(item -> item.getTrader().getCity().equals("Cambridge")).map(item -> item.getTrader().getName()).sorted(String::compareTo).distinct().collect(Collectors.toList());
System.out.println("3、"+cambridge1);
// (4) 返回所有交易员的姓名字符串,按字母顺序排序。
List<String> collect2 = transactions.stream().map(item -> item.getTrader().getName()).distinct().sorted(Collator.getInstance(Locale.CHINA)).collect(Collectors.toList());
System.out.println("4、"+collect2);
// (5) 有没有交易员是在米兰工作的?
boolean milan = transactions.stream().map(item -> item.getTrader().getCity()).anyMatch(("Milan"::equals));
System.out.println("5、"+milan);
// (6) 打印生活在剑桥的交易员的所有交易额。
List<Integer> cambridge = transactions.stream().filter(item -> item.getTrader().getCity().equals("Cambridge")).map(item -> item.getValue()).collect(Collectors.toList());
System.out.println("6、"+cambridge);
// (7) 所有交易中,最高的交易额是多少?
Integer integer1 = transactions.stream().map(item -> item.getValue()).max(Comparator.comparingInt(o -> o)).get();
System.out.println("7、"+integer1);
// (8) 找到交易额最小的交易。
Integer integer = transactions.stream().map(item -> item.getValue()).min(Comparator.comparingInt(o -> o)).get();
System.out.println("8、"+integer);
// 能使用方法引用的尽量用方法引用。
}
}
输出结果为: