流是从支持数据处理操作的源生成的元素序列。Stream流不是一种数据结构,不保存数据,它只是在原数据集上定义了一组操作,并且流只能遍历一次
流分为三部分
- 数据源
- 中间操作。诸如filter或sorted等中间操作会返回另一个流
- 终端操作。终端操作会从流的流水线生成结果。其结果是任何不是流的值,比如List、 Integer,甚至void。
过滤元素
- filter
过滤
过滤出大于2的数据
List<Integer> list = new ArrayList<>();
List<Integer> results = list.stream().filter(a -> a > 2).collect(Collectors.toList());
- distinct
过滤掉重复值
list.stream().filter(a -> a > 2).distinct().forEach(System.out::println);
- limit
返回前n个元素
list.stream().limit(2).collect(Collectors.toList()).forEach(System.out::println);
- skip
跳过前n个元素,返回剩下的元素,如果超过了元素长度,那么返回空流
list.stream().skip(3).collect(Collectors.toList()).forEach(System.out::println);
映射元素
- Map(T -> R)
替换list中的某个值,将流中的每一个元素T映射为R(类似类型转换)
# map用法, 将 list中的值都减1
lists.stream().map(aa -> aa - 1).collect(Collectors.toList());
#至取出对象中的某个属性
asList(new Ae("张三"), new Ae("李四"), new Ae("高五")).stream().map(Ae::getName).forEach(System.out::println);
flatMap
将list合并。将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流
// 输出list中不重复的元素
// Arrays.stream()的方法可以接受一个数组并产生一个流
这句话是先用map把他分为[a,b,c][b,c,d],然后再用flatMap,把两个数组合并为a,b,b,c,d,e的stream,然后再用distinct去重
List<String> list = new ArrayList<>();
list.add("abc");
list.add("bcd");
list.stream().map(a -> a.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList()).forEach(System.out::println);
// 将两个list合并
Stream.of(list, list2).flatMap(Collection::stream).collect(Collectors.toList());
//给定列表[1, 2, 3]和列表[3, 4],应该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
// 先将一个list转为流,然后用flatmap去合并,每取出一个元素,就将它跟list2中的每个元素组成新的元素
List<Integer[]> collect = list.stream().flatMap(a -> list2.stream().map(b -> new Integer[]{a, b})).collect(Collectors.toList());
//如果继续筛选,只列出两个数值加起来大于3的呢
List<Integer[]> collect = list.stream().flatMap(a -> list2.stream().filter(b -> (a+b)> 3).map(b -> new Integer[]{a, b})).collect(Collectors.toList());
查找匹配
- anyMatch
判断的条件里,任意一个元素成功,返回true
boolean b = list.stream().anyMatch(a -> a == 2);
- allMatch
判断条件里的元素,所有的都是,返回true
boolean b = list.stream().allMatch(a -> a == 2);
- noneMatch
条件里的元素,所有的都不是,返回true
boolean b = list.stream().noneMatch(a -> a == 2);
- findany
findAny方法将返回当前流中的任意元素。经过试验, 它总是返回列表中的第一个元素,所以百度了下说,findAny并不是随机地选一个,如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行的情况,那就不能确保是第一个
Integer integer = list.stream().findAny().get();
- findFirst
找到第一个元素
Integer integer = list.stream().findFirst().get();
规约
- reduce
求和, 第一个参数是起始数,可以为空,acc是上一轮acc和当前元素的和,element为当前元素。
#1
Integer sumInt = asList(1, 2, 5).stream().reduce(0, (acc, element) -> acc + element);
# 2
Integer aaa = asList(1, 2, 5).stream().reduce( (acc, element) -> acc + element).get();
// 也可以用reduce求最大最小值
Long aLong = asList(1, 2, 5).stream().reduce((a, b) -> a > b ? a : b).get();
- Max和Min
// 求对象某属性的最小值
Ab ab = list.stream().min(Comparator.comparing(Ab::getCount)).get();
// 直接求最小值
Integer integer = Stream.of(8, 2, 3).min(Comparator.comparing(Integer::intValue)).get();
Stream.of(int1, int2).flatMap(as -> as.stream()).collect(Collectors.toList());
asList("aaa bbb ccc").stream()
.map(a -> a.split(" ")).flatMap(Arrays::stream).collect(Collectors.toList()).forEach(System.out::println);
- sorted
从小到大
asList(1, 2, 5).stream().sorted().collect(Collectors.toList());
#从大到小
asList(1, 2, 5).stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
#从大到小
asList(1, 5,2,4,8).stream().sorted((a, b) -> b -a).collect(Collectors.toList()).forEach(System.out ::println);
#从大到小
list.stream().sorted(Comparator.comparingInt(Person::getAge )).collect(Collectors.toList());
测试
// 两个类
@Data
public class Trader {
private final String name;
private final String city;
}
@Data
public class Transaction {
private final Trader trader;
private final int year;
private final int value;
}
public static void main(String[] args) {
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)
);
// 找出2011年发生的所有交易,并按交易额排序(从低到高)。
transactions.stream().filter(a -> a.getYear() == 2011).sorted(Comparator.comparing(Transaction::getValue))
.collect(Collectors.toList()).forEach(System.out::println);
System.out.println("---------------------");
// (2) 交易员都在哪些不同的城市工作过?
transactions.stream().map(a -> a.getTrader().getCity()).distinct().collect(Collectors.toList()).forEach(System.out::println);
System.out.println("---------------------");
// (3) 查找所有来自于剑桥的交易员,并按姓名排序。
transactions.stream().map(Transaction::getTrader).filter(a -> "Cambridge".equals(a.getCity())).distinct()
.sorted(Comparator.comparing(Trader::getCity))
.collect(Collectors.toList()).forEach(System.out::println);
System.out.println("---------------------");
// (4) 返回所有交易员的姓名字符串,按字母顺序排序。
String str = transactions.stream().map(a -> a.getTrader().getName()).distinct().sorted()
.reduce((a, b) -> a + b).get();
System.out.println(str);
// 第二种方式
String str2 = transactions.stream().map(a -> a.getTrader().getName()).distinct().sorted()
.collect(joining());
System.out.println(str2);
System.out.println("---------------------");
// (5) 有没有交易员是在米兰工作的?
System.out.println(transactions.stream().anyMatch(a -> "Milan".equals(a.getTrader().getCity())));
System.out.println("---------------------");
// (6) 打印生活在剑桥的交易员的所有交易额。
transactions.stream().filter(a -> "Cambridge".equals(a.getTrader().getCity()))
.forEach(a -> System.out.println(a.getValue()));
System.out.println("---------------------");
// (7) 所有交易中,最高的交易额是多少?
System.out.println(transactions.stream().max(Comparator.comparing(Transaction::getValue)).map(Transaction::getValue).get());
System.out.println("---------------------");
// (8) 找到交易额最小的交易。
System.out.println(transactions.stream().min(Comparator.comparing(Transaction::getValue)).map(Transaction::getValue).get());
}
数据流
- 原始类型流特化
IntStream、 DoubleStream和LongStream,分别将流中的元素特化为int、 long和double,从而避免了暗含的装箱成本。
int sum = goods.stream().mapToInt(Goods::getPrice).sum()
- 再将数值流转为非特华流
IntStream intStream = goods.stream().mapToInt(Goods::getPrice);
Stream<Integer> stream = intStream.boxed();
- 生成数据范围
// 生成从1到100的数据流
IntStream evenNumbers = IntStream.rangeClosed(1, 100);
创建流
-
由值创建流
Stream.of("ge","ge").forEach(System.out::print);
- 由数组创建流
Arrays.stream(new int[]{1,2,3,4}).forEach(System.out::print);
- 文件创建流
System.out.println(Files.lines(Paths.get("C:\\Users\\HASEE\\Desktop\\aa.txt"), StandardCharsets.UTF_8)
.flatMap(line -> Arrays.stream(line.split(" ")))
.distinct()
.collect(Collectors.joining()));
- 函数生成流
// 迭代方式
Stream.iterate(0, a -> a + 1).limit(50).forEach(System.out::println);
// 生成
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
面试问过的例子
JDK1.8 中list<bean>转为 Map<id,name>
Map<Integer, String> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, Apple::getName );
读取文件
List<String> strs = Files.lines(Paths.get(fileName), Charset.defaultCharset()).collect(Collectors.toList());
或者
List<String> lineLists = Files
.lines(Paths.get(fileName), Charset.defaultCharset())
.flatMap(line -> Arrays.stream(line.split(",")))
.collect(Collectors.toList());