Java 8编程进阶-Stream之函数式编程

1、什么是Stream

       Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

    总之,中间操作只是创建另一个流,不会执行任何处理,直到最终操作被调用。一旦最终操作被调用,则开始遍历所有的流,并且相关的函数会逐一应用到流上。中间操作是惰性操作,所以,流支持惰性,下面是一些函数的分类。


Stream操作分类
中间操作(Intermediate operations) 无状态(Stateless) unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek()
有状态(Stateful) distinct() sorted() sorted() limit() skip()
最终操作(Terminal operations) 非短路操作 forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
短路操作(short-circuiting) anyMatch() allMatch() noneMatch() findFirst() findAny()


2、流的使用

2.1、获取Stream

在使用流之前,首先需要拥有一个数据源,并通过StreamAPI提供的一些方法获取该数据源的流对象。数据源可以有多种形式:

(1)集合 
这种数据源较为常用,通过stream()方法即可获取流对象:

   List list = new ArrayList<>();
   Stream stream = list.stream();

(2)数组 
通过Arrays类提供的静态函数stream()获取数组的流对象:

   String[] array = {"a","b","c"};
   Stream<String> stream = Arrays.stream(array);

(3)值 
直接将几个值变成流对象:

   Stream<String> stream = Stream.of("a""b""c");


2.2、forEach

对流中的每个元素执行一些操作。

    List list = new ArrayList<>(Arrays.asList("a","b","c"));
    //写法一
    list.stream().forEach(x -> {
        System.out.println(x);
    });
    //写法二
    list.stream().forEach(System.out::println);

2.3、map

接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

    List list = new ArrayList<>(Arrays.asList("a","b","c"));
    //写法一
    list.stream().forEach(x -> {
        System.out.println(x);
    });
    //写法二
    list.stream().forEach(System.out::println);

2.4、flatMap

接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

    List list = new ArrayList<>(Arrays.asList("a,1","b,2","c,3"));

    List newList = list.stream().flatMap(x->{
        String[] array = x.split(",");
        return Arrays.stream(array);
    }).collect(Collectors.toList());

结果:

[a, 1, b, 2, c, 3]

2.5、reduce()

通过一个二进制操作将流中的元素合并到一起。

    List list = new ArrayList<>(Arrays.asList(123));
    //写法一,累加不带初始值
    Optional accResult = list.stream().reduce((acc, item) -> {
        acc += item;
        return acc;
    });

输出6

    //写法一,累加带初始值10
    int result1 = list.stream().reduce(10(acc, item) -> {
        acc += item;
        return acc;
    });

输出16

2.6、filter()

过滤元素

    List list = new ArrayList<>(Arrays.asList(123,4));
    List newList = list.stream().filter(x -> x >=3).collect(Collectors.toList());

输出[3,4]

2.7、distinct()

去除重复元素

    List list = new ArrayList<>(Arrays.asList(111,2,2));
    List newList = list.stream().distinct().collect(Collectors.toList());

输出结果

[1,2]

2.8、collect() 

将流中的元素倾倒入某些容器

(1)toList

将元素转成List,很简单,上面的实例很多

(2)toSet

将元素转成Set

    List<Integer> list = new ArrayList<>(Arrays.asList(11122));
    Set<Integerset = list.stream().collect(Collectors.toSet());

 (3) toMap

将元素转成Map

用法可以如下

public Map getIdNameMap(List accounts) {

return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));
}

收集成实体本身map

代码如下:

public Map getIdAccountMap(List accounts) {
return accounts.stream().collect(Collectors.toMap(Account::getId, account -> account));
}

account -> account是一个返回本身的lambda表达式,其实还可以使用Function接口中的一个默认方法代替,使整个方法更简洁优雅:

public Map getIdAccountMap(List accounts) {
return accounts.stream().collect(Collectors.toMap(Account::getId, Function.identity()));
}

重复key的情况

代码如下:

public Map getNameAccountMap(List accounts) {
return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity()));
}

这个方法可能报错(java.lang.IllegalStateException: Duplicate key),因为name是有可能重复的。toMap有个重载方法,可以传入一个合并的函数来解决key冲突问题:

public Map getNameAccountMap(List accounts) {
return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity()(key1, key2) -> key2));
}

这里只是简单的使用后者覆盖前者来解决key重复问题。

指定具体收集的map

toMap还有另一个重载方法,可以指定一个Map的具体实现,来收集数据:

public Map getNameAccountMap(List accounts) {
return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity()(key1, key2) -> key2LinkedHashMap::new));
}

2.8、min()  
根据一个比较器找到流中元素的最小值。

BigDecimal min = planList.stream().min((a,b)->a.getPrice().compareTo(b.getPrice())).get().getPrice();

2.9、max() 

根据一个比较器找到流中元素的最大值。

BigDecimal max = planList.stream().max((a,b)->a.getPrice().compareTo(b.getPrice())).get().getPrice();

2.10、count() 

计算流中元素的数量。

    List list = new ArrayList<>(Arrays.asList(14233,101,6));
    long min = list.stream().distinct().count();


你可能感兴趣的:(Java并发编程与技术内幕)