0
点赞
收藏
分享

微信扫一扫

java8 新特性Stream

概要

首先要澄清的是 java8 中的stream 与InputStream和OutputStream是完全不同的概念, stream 是用于对集合迭代器的增强,使之完成 能够完成更高效的聚合操作(过滤排序统计分组)或者大批量数据操作。此外与stream 与lambda 表达示结合后编码效率与大大提高,并且可读性更强。

应用场景:数据源从多个地方汇集而来(必须从多个数据库中查到的数据)



@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class AppleStore {
private Integer id;
private String color;
private Integer weight;
}


示例展示1:

// 获取所有红色苹果的总重量
List<AppleStore> appleStoreList = Arrays.asList(
new AppleStore(1, "red", "10"),
new AppleStore(2, "blue", "11"),
new AppleStore(3, "blue", "13"),
new AppleStore(4, "red", "11")
);
int sums = appleStoreList
.stream()
.filter(x -> "red".equals(x.getColor()))
.mapToInt(n -> Integer.parseInt(n.getWeight()))
.sum();
System.out.println(sums);

java8 新特性Stream_json

示例展示2:

基于水果的颜色,求出水果平均重量;

// 基于颜色统计平均重量
List<AppleStore> appleStoreList = Arrays.asList(
new AppleStore(1, "red", "10"),
new AppleStore(2, "blue", "11"),
new AppleStore(3, "blue", "13"),
new AppleStore(4, "red", "11")
);
Map<String, Double> map = appleStoreList.stream()
.collect(Collectors.groupingBy(
x -> x.getColor(),
Collectors.averagingInt(x -> Integer.parseInt(x.getWeight()))
));
System.out.println(JSON.toJSONString(map));

 java8 新特性Stream_数组_02

java8 新特性Stream_数组_03

stream 产生背景

‘获取所有红色苹果的总重量’,如果用SQL其实非常好实现,为什么不在直接关系数据库来实现呢?

//获取所有红色苹果的总重量
select sum(a.weight) from apple as a  where a.color='red';
// 基于颜色分组统计重量
select a.color,sum(a.weight) from apple as a group by color;

遍历在传统的javaEE 项目中数据源比较单一而且集中,像这类的需求都我们可能通过关系数据库中进行获取计算。但现在的互联网项目数据源成多样化有:关系数据库、NoSQL、Redis、mongodb、ElasticSearch、Cloud Server 等。这时就需我们从各数据源中汇聚数据并进行统计。这在Stream出现之前只能过遍历实现 非常繁琐。

创建流方式:

1、Stream.of(T... val) 参数是多参泛型

Stream s1 = Stream.of("1", "2", "3");

java8 新特性Stream_json_04

2、Arrays.stream(T[]) 参数是数组

IntStream s2 = Arrays.stream(new int[]{1, 2, 3});

java8 新特性Stream_数据源_05

3、集合、 列表 .stream()

List<Integer> r = new ArrayList<>();
Stream s = r.stream();

流的执行过程

java8 新特性Stream_数组_06

 流组成

1、创建流.中间节点.中间节点.··· ···.终止节点;

list.stream().filter().limit().toArray()

中间节点:一般返回的是一个流,后边可以继续调用;
终止节点:返回的不是一个流,一般返回一个结果集。

Integer[] r = {1, 2, 3};
Object[] s = Arrays.stream(r).limit(2).toArray();
List<AAA> a = Arrays.asList(
new AAA("1", 20),
new AAA("2", 22),
new AAA("3", 23),
new AAA("4", 24)
);
Object res = a.stream().filter(x -> x.getAge() > 22).toArray();

中间节点的影响

(1)过滤

经过filter过滤函数之后,后边只能操作过滤之后的数组了。

Integer[] r = {1, 2, 3, 4, 5};
Object[] s = Arrays.stream(r).filter(x -> x >= 3).limit(2).toArray();
System.out.println(JSON.toJSONString(s));

java8 新特性Stream_数组_07

 (2)转换

经过map函数会把集合中的每一个AAA转化为以 年龄组成的集合。 

List<AAA> a = Arrays.asList(
new AAA("1", 20),
new AAA("2", 22),
new AAA("3", 23),
new AAA("4", 24)
);
Object res = a.stream().filter(x -> x.getAge() >= 22)
.map(x -> x.getAge())
.toArray();
System.out.println(JSON.toJSONString(res));

java8 新特性Stream_数组_08

(3)去重

distinct() 去重

Integer[] i = new Integer[]{1, 1, 2, 2, 3, 4, 3, 2};
Object[] a = Arrays.stream(i).filter(x -> x >= 2).distinct().toArray();
System.out.println(JSON.toJSONString(a));

java8 新特性Stream_数组_09

stream流的debugger模式

这个要靠idea了,查看当前流的链。

java8 新特性Stream_数组_10

 很清晰,每一个过滤函数执行、去重、之后的结果,执行:

java8 新特性Stream_数据源_11

 

中间节点方法有哪些

除了上边的filter 、map、distinct、sorted()排序


方法



描述



操作类型



filter



接收一个Boolean表达示来过滤元素



中间操作



map



将流中元素 1:1 映谢成另外一个元素



中间操作



mapToInt



将流中元素映谢成int,mapToLong、mapToDouble操作类似目的减少 装箱拆箱带来的损耗



中间操作



flatMap



如map时返回的是一个List, 将会进一步拆分。详见flatMap示例



中间操作



forEach



遍历流中所有元素



终值操作



sorted



排序     x,y -> x.getID - y.getID



中间操作



peek



遍历流中所有元素 ,跟forEach不同在于不会结束流



中间操作



toArray



将流中元素转换成一个数组返回



终值操作



reduce



归约合并操作
关于reduce方法,详情查看这篇文章,很不错:
​​​javascript:void(0)​​



中间操作



collect



采集数据,返回一个新的结果

参数说明:

Supplier<R>: 采集需要返回的结果

BiConsumer<R, ? super T>:传递结果与元素进行合并。

BiConsumer<R, R>:在并发执行的时候 结果合并操作。详见 collec示例




终值操作



distinct



基于equal 表达示去重



中间操作



max



通过比较函数 返回最大值



终值操作



anyMatch



流中是否有任一元素满足表达示



终值操作



allMatch



流中所有元素满足表达示返回true



终值操作



noneMatch



与allMatch 相反,都不满足的情况下返回 true



终值操作



findFirst



找出流中第一个元素



终值操作



of



生成流



生成流操作



iterate



基于迭代生成流



生成流操作



generate



基于迭代生成流,与iterate 不同的是不 后一元素的生成,不依懒前一元素



生成流操作



concat



合并两个相同类型的类



生成流操作


1、peek() 执行函数、forEach()执行函数

peek和forEach都是执行函数,不会做任何过滤操作,只是执行。
区别:peek是中间节点,可以往后继续调用,而forEach是终止节点。

Integer[] i = new Integer[]{1, 1, 2, 2, 3, 4, 3, 2};
Arrays.stream(i).filter(x -> x >= 2)
.distinct()
.peek(n -> System.out.println(n)).toArray();

java8 新特性Stream_数据源_12

 2、collect 采集

很重要

· 把结果转化为一个list
· 把结果转化为map
· 把结果分组
· 转化为数组
· 求最大值
· 求任意值

来看几个

1、把结果转化为 map集合,键为:id,值为:对象
结果转化为map时,如果key有重复的,会报错,当然你可以在加一个策略toMap(k, y, z),参数z可以把重复的去掉。

// Person
@Data
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class AAA {
private Integer id;
private String name;
private Integer age;
}
List<Person> a = Arrays.asList(
new Person(1, "1", 20),
new Person(2, "2", 22),
new Person(3, "3", 23),
new Person(4, "4", 24)
);
Map<Integer, Person> res = a.stream()
.filter(x -> x.getAge() >= 22)
// key value
.collect(Collectors.toMap(n -> n.getId(), n -> n));
System.out.println(JSON.toJSONString(res, SerializerFeature.PrettyFormat));

java8 新特性Stream_数组_13

补充下:

内置的四个函数式接口

1、Consumer<T> 消费型接口

无参数,无参返回值。

public static void main(String[] args) {
// Consumer 消费型接口
t(10, System.out::println);
}
static public void t(Integer sum, Consumer<Integer> consumer) {
consumer.accept(sum);
}

java8 新特性Stream_数组_14

2、Supplier<T> 供给型接口

无参数,有返回值。

public static void main(String[] args) {
String r = "abc";
// Supplier 供给型接口
// new Random().nextInt(10) 随机生成[0~10)之间整数
String res = JSON.toJSONString(t(10, () -> new Random().nextInt(10)));
System.out.println(res);
}
static public List<Integer> t(Integer n, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<>();
for (Integer i = 0; i < n; i++) {
list.add(supplier.get());
}
return list;
}

3、Function<T, V> 函数型接口

有参数,有返回值。

@FunctionalInterface
public interface Function<T, R> {
    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

}

public static void main(String[] args) {
// Function 函数型接口
System.out.println(t(" a ", x -> x.trim()));
}
static public String t(String str, Function<String, String> function) {
return function.apply(str);
}

4、Predicate<T> 断言型接口

有参,返回布尔值。

@FunctionalInterface
public interface Predicate<T> {
    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

public static void main(String[] args) {
// Predicate 断言型接口
System.out.println(t("abc", "abc"::equals));
}
static public boolean t(String str, Predicate<String> predicate) {
return predicate.test(str);
}


举报

相关推荐

0 条评论