Stream数据流
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性
当我们需要使用一个流时,通常包含三个基本步骤:
1.获取数据源
2.数据转换
3.执行操作获得想要的结果,每次操作都会返回一个新的Stream流对象,可以通过多次操作形成一个链条的形式逐步处理数据达到想要的结果。
流的操作分为两种:
Intermediate(中间操作):一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
Terminal(终端操作):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
流是一个懒加载的模式 未结束流前不会进行操作,只要结束流以后才会操作返回结果.
中间操作(Intermediate operations):
- map()
- mapToInt() mapToLong() mapToDouble()
- flatMap() flatMapToInt() flatMapToLong() flatMapToDouble()
- filter()
- peek()
- unordered()
- distinct()
- sorted()
- limit()
- skip()
终端操作(Terminal operations)
- forEach()
- toArray()
- reduce()
- collect()
- max()
- min()
- count()
- anyMatch() allMatch() noneMatch()
- findFirst()
- findAny()
将集合流化的数据执行了终结流的方法后,不能再对此流进行操作,否则系统会抛异常IllegalStateException
从JDK1.8开始,Collection口里面除了定义一些抽象方法外,也提供了一些普通方法
1.利用forEach输出
List<String> list = new ArrayList<>();
//1.forEach 来自于Iterable
Collections.addAll(list,"php", "java", "go");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//lambda表达式
list.forEach(s -> {
System.out.println(s);
});
List<String> list = new ArrayList<>();
//2.Stream来自于Collection
System.out.println(list.stream().count());
//若包含Java则遍历打印
list.stream()
.filter(s->s.contains("java"))
.map(s->s.toUpperCase())//将list元素转为大写
.forEach(System.out::println);
//普通写法,将集合中的元素转为大写放入另一个集合
List<String> newList=new ArrayList<>();
for(String item:list){
if (item.contains("java")){
newList.add(item.toUpperCase());
}
}
System.out.println(newList);
//利用stream写法
List<String> newList1=list.stream()
.filter(s->s.contains("java"))//断言函数,进行数据过滤
.map(s->s.toUpperCase())
.collect(Collectors.toList());//Collectors.toList()收集器作用
System.out.println(newList1);
//将Integer转为String
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(11);
list1.add(111);
List<String> list2=list1
.stream()
.map(s->String.valueOf(s))
.collect(Collectors.toList());
//符合条件的个数统计
long count=list.stream().filter(s -> s.contains("java")).count();
System.out.println(count);
System.out.println("---------------------");
//skip与limit方法实现分页
list.stream()
.skip(1)//跳过1个
.limit(2)//取2个
.forEach(System.out::println);
System.out.println("----------------------");
list.stream()
.skip(0)
.limit(1)
.forEach(System.out::println);
}
Collection接口里提供有一个重要的stream()方法,将集合数据交给Stream之后,就相当于这些数据一个一个进行处理.且支持多线程,高并发,多核内存利用
MapReduce基础模型:
public class Order {
private String titile;
private double price;
private int amount;
public Order(String titile, double price, int amount) {
this.titile = titile;
this.price = price;
this.amount = amount;
}
public String getTitile() {
return titile;
}
public void setTitile(String titile) {
this.titile = titile;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
public class MapReduce {
public static void main(String[] args) {
List<Order> orderList = new ArrayList<>();
orderList.add(new Order("iphone", 8999.99, 122));
orderList.add(new Order("外行星人笔记本", 8969.99, 12));
orderList.add(new Order("MacBook", 1899.22, 5));
orderList.add(new Order("javaBook", 78, 122));
orderList.add(new Order("中性笔", 2, 67));
//计算金额综合
double total=0.0;
for(Order order:orderList){
total+=order.getPrice()*order.getAmount();
}
System.out.println("总金额是:"+total);
//利用MapReduce计算 fork-join
orderList.stream()
.mapToDouble(o->o.getPrice()*o.getAmount())
//将DoubleStream中的每个元素求和
.reduce(new DoubleBinaryOperator() {
@Override
//left->sum right ->map()中的每个数据
public double applyAsDouble(double left, double right) {
return left+right;
}
}).orElseGet(new DoubleSupplier() {
@Override
public double getAsDouble() {
return 0;
}
});
//mapreduce统计分析
DoubleSummaryStatistics ds= orderList.stream().mapToDouble(o->o.getAmount()*o.getPrice())
.summaryStatistics();
//统计结果:订单数量,最大订单 最小订单 总额 平均值
System.out.println("订单数量"+ds.getCount());
System.out.println("最大订单"+ds.getMax());
System.out.println("最小订单"+ds.getMin());
System.out.println("总额"+ds.getSum());
System.out.println("平均值"+ds.getAverage());
group();
}
public static void group(){
List<Order> orderList = new ArrayList<>();
orderList.add(new Order("MacBook", 1899.22, 5));
orderList.add(new Order("MacBook", 1899.22, 5));
orderList.add(new Order("javaBook", 78, 122));
orderList.add(new Order("中性笔", 2, 67));
orderList.add(new Order("中性笔", 2, 67));
Map<String, List<Order>> map = new HashMap<>();
for(Order order:orderList){
if(map.containsKey(order.getTitile())){
map.get(order.getTitile()).add(order);
}else{
List<Order> orders=new ArrayList<>();
orders.add(order);
map.put(order.getTitile(), orders);
}
}
//计算title相同的订单金额(原逻辑)
Map<String, Double> doubleMap = new HashMap<>();
for(Map.Entry<String,List<Order>> entry:map.entrySet()){
String title=entry.getKey();
List<Order> orders=entry.getValue();
double sum=0.0D;
for(Order o:orders){
sum+=o.getPrice()*o.getAmount();
}
doubleMap.put(title, sum);
}
System.out.println(doubleMap);
//MapReduce 实现分组
orderList.stream()
//title作为标识分组
.collect(Collectors.groupingBy(o -> o.getTitile()))
.forEach((k,v)->{
//为各组赋值key为title,value为每组的订单的和
//mapToDouble计算每个订单的金额
doubleMap.put(k,v.stream().mapToDouble(o->o.getAmount()*o.getPrice())
//reduce计算每组订单金额的和
.reduce((sum,x)->sum+x).orElse(0));
});
}
}