专栏首页springboot解析4.2.Java8 Stream简单的应用
原创

4.2.Java8 Stream简单的应用

流的简介

简短的定义:从支持数据处理操作的源生成的元素序列

剖析这个定义

        元素序列:像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值,因为集合是数据结构,所以他的主要目的是以特定的时间/空间复杂度存储和访问元素,但流的目的在于表达计算。集合讲的是数据,流讲的是计算。

        源:流会使用一个提供数据的源,如集合、数组或输入/输出资源。请注意,从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素序列与列表一致。

       数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行也可以并发执行。 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个流水线。

     内部迭代:与使用迭代器显示迭代的集合不同,流的迭代操作是在背后进行的。

java8 Stream(流)常见的操作主要有以下几个方面

1)过滤筛选:filter

    stream 接口支持filter方法,该操作接收一个谓词Predicate(一个返回bollean的函数)作为参数,并返回一个所有符合谓词元素的流。

2)排序:sort

3)去重:distinct

4)映射:map

    map方法,它会接收一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素。

5)查找匹配:anyMatch、allMatch、noneMatch、findFirst、findAny

    anyMatch:流中是否有一个元素能匹配给定的谓词。

    allMath:流中所有元素是否能匹配给定的谓词。

    noneMath:可以确保流中没有任何元素与给定的谓词匹配。

    findAny:返回当前流中的任意元素。

    findFirst:返回流中的第一个元素。

findAny 和 findFirst 有什么区别?

        答案是并行,找到一个元素在并行上限制有很多,如果不关心返回的那个元素,请使用findAny,因为它在使用并行流时限制很少。

6)归约和汇总:reduce、groupingBy

    reduce:接收两个参数,归约函数

            1)一个初始值,

            2)一个 BinaryOperator<T> 来将两个元素结合起来产生一个新值, 

                    求和用lambda    (a,b) ->a+b

                    求积用lambda    (a,b) ->a*b

    groupingBy:对流按照元素进行分组

        Map<Currency,List<Transaction>>  transactionByCurrencies =

                    transactions.stream().collect(groupingBy(Transaction::getCurrency));

7)截短流

    流支持limit(n),该方法返回一个不超过给定长度的流,所需长度作为常数传递给limit。如果流是有序的,则最多返回前n个元素。请注意,limit也可以用在无序流上,比如源是一个set,这种情况,limit的结果不会以任何顺序排列。

8)跳过元素

    流支持ship(n)方法,返回一个扔掉前n个元素的流,如果流中元素不足n个,怎返回一个空流,注意 limit 和 ship 是互补的。

9)流的扁平化(稍后会有专门的一篇文章来讲解流的扁平化)

    flatMap方法,可以将生成的单个流合并起来,即扁平化一个流。

2.Java8 Stream经典示例

示例一:现在有一个List<User> 的集合,如何把这个list转换成Map<Integer, User> 其中,key是user id,value是User对象

class User {

private int id;

private String name;

public User(int id, String name) {

this.id = id;

this.name = name;

}

public int getId() {

return id;

}

public String toString() {

return "User [id=" + id + ", name=" + name + "]";

}

}

代码如下:

List<User> users = Arrays.asList(new User(1, "Tomcat"), new User(2, "Apache"), new User(3, "Nginx"));

Map<Integer, User> map = users.stream().collect(Collectors.toMap(obj -> obj.getId() , obj -> obj));

System.out.println(map);

或者使用方法的引用

Map<Integer, User> map = users.stream().collect(Collectors.toMap(User::getId , obj -> obj));

最后,输出结果

{1=User [id=1, name=Tomcat], 2=User [id=2, name=Apache], 3=User [id=3, name=Nginx]}

示例二:如何把list中的每个map中的id取出来,转换成list<String>

有如下List<Map<String, String>>

List<Map<String, String>> list = new ArrayList<>();

Map<String, String> map1 = new HashMap<>();

map1.put("id", "101");

map1.put("name", "Tomcat");

Map<String, String> map2 = new HashMap<>();

map2.put("id", "102");

map2.put("name", "Apache");

Map<String, String> map3 = new HashMap<>();

map3.put("id", "103");

map3.put("name", "Nginx");

list.add(map1);

list.add(map2);

list.add(map3);

参考代码如下:

List<String> ids = list.stream().map(entity -> entity.get("id")).collect(Collectors.toList());

System.out.println(ids);

或者

List<Object> ids = Arrays.asList(list.stream().map(entity -> entity.get("id")).toArray());

输出结果:

[101, 102, 103]

示例三:如何把url的请求参数(如:type=1&from=APP&source=homePage)转换成Map<String, String>

参考代码:

String queryString = "type=1&from=APP&source=homePage";

Map<String, String> map = Stream.of(queryString.split("&")).map(obj -> obj.split("=")).collect(Collectors.toMap(entry -> entry[0], entry -> entry[1]));

System.out.println(map);

输出结果:

{from=APP, source=homePage, type=1}

示例四:把List<String>转换成List<Integer>

List<String> strs = Arrays.asList("1","2","3");

List<Integer> ints = strs.stream().map(obj -> Integer.valueOf(obj)).collect(Collectors.toList());

示例五:执行交易的交易员。你的经理让你为八个查询找到答案

1)找出2011年发生的所有交易,并且按照交易额排序(从低到高)
2)交易员都在哪些不同城市工作过
3)查找所有来自于剑桥的交易员,并且按照姓名排序
4)返回所有交易员的姓名字符串,按字母排序
5)有没有交易员是在米兰工作过?
6)打印生活在剑桥的交易员所有交易额。
7)所有交易中,最高的交易额是多少?
8)找到交易额的最小的交易。

代码实现

实体类创建:

//交易员

public class Trader {
    private final  String name;
    private final  String city;

    public Trader(String n, String c) {
        this.name = n;
        this.city = c;
    }

    public String getCity() {
        return city;
    }

    public String getName() {
        return name;
    }

    public String toString(){
        return "{"+"Trader:"+this.name+"in " + this.city;
    }
}

实体类创建:

//交易信息类

public class Transaction {
    private final Trader trader;
    private final int year;
    private final int value;

    public Transaction(Trader trader, int year, int value){
        this.value = value;
        this.year = year;
        this.trader = trader;
    }

    public Trader getTrader(){
        return  this.trader;
    }
    public int getValue() {
        return value;
    }

    public int getYear() {
        return year;
    }

    public String toString(){
        return "{"+this.trader+","+"year:"+this.year+","+"value:"+this.value+"}";
    }
}

八种查询实现

/*测试用例:执行交易的交易员。你的经理让你为八个查询找到答案
1)找出2011年发生的所有交易,并且按照交易额排序(从低到高)
2)交易员都在哪些不同城市工作过
3)查找所有来自于剑桥的交易员,并且按照姓名排序
4)返回所有交易员的姓名字符串,按字母排序
5)有没有交易员是在米兰工作过?
6)打印生活在剑桥的交易员所有交易额。
7)所有交易中,最高的交易额是多少?
8)找到交易额的最小的交易。
* */
public class learnStream {
    public static  void main(String arg[]){
        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年发生的所有交易,并且按照交易额排序(从低到高)
        List<Transaction> tr2011 = transactions.stream()
                .filter(transaction ->transaction.getYear() == 2011)
                .sorted(Comparator.comparing(Transaction::getValue))
                .collect(toList());

        //2)交易员都在哪些不同城市工作过
        List<String> cities = transactions.stream()
                .map(transaction -> transaction.getTrader().getCity())
                .distinct()
                .collect(toList());

        //3)查找所有来自于剑桥的交易员,并且按照姓名排序
        List<Trader> name = transactions.stream()
               .map(transaction -> transaction.getTrader())
                .filter(trader -> trader.getCity().equals("Cambridge"))
                .distinct()
                .sorted(Comparator.comparing(Trader::getName))
                .collect(toList());

        //4)返回所有交易员的姓名字符串,按字母排序
        String traderStr = transactions.stream()
                .map(transaction -> transaction.getTrader().getName())
                .distinct()
                .sorted()
                .reduce("",(n1,n2) -> n1+n2);
        String traderStr2 = transactions.stream()
                .map(transaction -> transaction.getTrader().getName())
                .distinct()
                .sorted()
                .collect(joining());

        //5)有没有交易员是在米兰工作过?
        boolean mailanBased = transactions.stream()
                .anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));

        //6)打印生活在剑桥的交易员所有交易额。
        transactions.stream()
                .filter(transaction -> transaction.getTrader().getCity().equals("Cambridge"))
                .map(Transaction::getValue)
                .forEach(System.out::println);

        //7)所有交易中,最高的交易额是多少?
        Optional<Integer> highestValue = transactions.stream()
                .map(transaction -> transaction.getValue())
                .reduce(Integer::max);

        //8)找到交易额的最小的交易。
        Optional<Transaction> smallestTransaction = transactions.stream()
                .min(Comparator.comparing(Transaction::getValue));

    }

}

示例六:将流中的数据转成集合类型

一、将数据收集进一个列表(Stream 转换为 List,允许重复值,有顺序)

//1.将数据收集进一个列表(Stream 转换为 List,允许重复值,有顺序)

//创建流

Stream<String> language = Stream.of("java", "python", "C++","php","java");

List<String> listResult = language.collect(Collectors.toList());

result.forEach(System.out::println);

//2.stream()代替流

List<String> list = Arrays.asList("java", "python", "C++","php","java");

List<String> listResult = list.stream().collect(Collectors.toList());

listResult.forEach(System.out::println);

输出结果为:

二、将数据收集进一个集合(Stream 转换为 Set,不允许重复值,没有顺序)

//1.将数据收集进一个集合(Stream 转换为 Set,不允许重复值,没有顺序)

Stream<String> language = Stream.of("java", "python", "C++","php","java");

Set<String> setResult = language.collect(Collectors.toSet());

setResult.forEach(System.out::println);

输出结果为:

三、用自定义的实现Collection的数据结构收集

List<String> list = Arrays.asList("java", "python", "C++","php","java");

//用LinkedList收集

List<String> linkedListResult = list.stream().collect(Collectors.toCollection(LinkedList::new));

linkedListResult.forEach(System.out::println);

System.out.println("--------------");

//用CopyOnWriteArrayList收集

List<String> copyOnWriteArrayListResult = list.stream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));

copyOnWriteArrayListResult.forEach(System.out::println);

System.out.println("--------------");

//用TreeSet收集

TreeSet<String> treeSetResult = list.stream().collect(Collectors.toCollection(TreeSet::new));

treeSetResult.forEach(System.out::println);

输出结果为:

四、对Stream的字符串拼接

List<String> list = Arrays.asList("java", "python", "C++","php","java");

//直接将输出结果拼接

System.out.println(list.stream().collect(Collectors.joining()));

//每个输出结果之间加拼接符号“|”

System.out.println(list.stream().collect(Collectors.joining(" | ")));

//输出结果开始头为Start--,结尾为--End,中间用拼接符号“||”

System.out.println(list.stream().collect(Collectors.joining(" || ", "Start--", "--End")));

输出结果为:

五、其他还有partitioningBy(),分类成一个key为True和Flase的Map。

例如

List<String> list = Arrays.asList("java", "python", "C++","php","java");

Map<Boolean, List<String>> result = list.stream().collect(partitioningBy(s -> s.length() > 2));

六、collectingAndThen(),收集之后继续做一些处理。

例如

List<String> list = Arrays.asList("java", "python", "C++","php","java");

//收集后转换为不可变List

ImmutableList<String> collect = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf));

总结:

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2.2.RedisTemplate 基本配置说明文档

    在Spring的应用中,redis可以算是基础操作了。那么想要玩转redis,我们需要知道哪些知识点呢?

    itjim
  • 4.1.java8新特性持续更新

    记得我在以前找工作的经历中,遇到过一个面试官问过我一个很基础的问题。问题是:有一个List中有10个元素,我现在想从中删除3个元素,请问怎么做?我...

    itjim
  • 2.1.RedisTemplate优雅地操作Redis

    如果你的数据需要被第三方工具解析,那么数据应该使用StringRedisSerializer而不是JdkSerializationRedisSerializer...

    itjim
  • 让代码更优雅:JAVA代码不同JDK版本的不同写法

    JDK不同版本有不同的特性,我刚毕业时候JDK1.8(8)已经出现了,但是大多公司还在用1.6(6),后面陆续出现了9、10、11、12,但是大多公司仍然坚守在...

    品茗IT
  • C#List<string>和string[]之间的相互转换

    aehyok
  • 比反射更快!使用ASM获取class信息(ClassReader)

    通常我们想要在java运行时获取class的信息时,通常使用反射的方式来获取其中的属性,方法,注解等信息。通常是这样的:

    何白白
  • Java 代码精简之道

    其中:“道”指“规律、道理、理论”,“术”指“方法、技巧、技术”。意思是:“道”是“术”的灵魂,“术”是“道”的肉体;可以用“道”来统管“术”,也可以从“术”中...

    JAVA葵花宝典
  • 微服务[学成在线] day13:使用FFmpeg进行格式转换以及m3u8文件生成、文件分块上传接口实现

    学成在线作为在线教育网站,提供多种学习形式,包括:录播、直播、图文、社群等,学生登录进入学习中心即可

    LCyee
  • 一文弄懂String的所有小秘密

    String是java中非常常用的一个对象类型。可以说java中使用最多的就是String了。

    程序那些事
  • Java入门 - 语言基础 - 14.String类

    原文地址:http://www.work100.net/training/java-string.html

    光束云

扫码关注云+社区

领取腾讯云代金券