Java8 Stream流操作学习总结

作者:一杯甜酒 原文:https://blog.csdn.net/u012562943/article/details/81775926

引言

传统的数据处理都是用循环来解决,而不是像搜索数据库那样有具体的搜索语句,而Java8的Stream提供了很好的方案,往往一行就搞定了,而且Stream还可以链式操作,一行代码实现多个循环的功能,代码风格十分像nosql数据库。

但是在实际应用中发现一个巨大的问题,就是执行耗时特别长,时间开销是传统方法的几百倍,这是一个巨大的问题。

Java8可以像操作数据库一样操作内存,而且在Stream操作中对内存的开销十分友善,操作方式十分灵活,减少了IO的支出。

下面是一个小例子代码:

package com.zhy.demo.javase.java8.stream;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
 
/**
 * @ClassName User
 * @Description (User类用来代表用户,里面有姓名年龄密码等常用字段)
 * @author ZHY
 * @date 2018年8月15日 下午11:15:26
 * @Copyright © 2018【www.zhy.com Inc. All rights reserved.】
 */
public class User implements Comparable<User> {
  /**
   * 年龄
   */
  private int age;
  /**
   * 姓名
   */
  private String name;
  /**
   * 密码
   */
  private String password;
 
  /**
   * 性别,0未知,1男,2女
   */
  private short gendar;
 
  /**
   * 是否已婚
   */
  private boolean hasMarried;
 
  public User() {
    super();
  }
 
  public User(int age, String name, String password, short gendar, boolean hasMarried) {
    super();
    this.age = age;
    this.name = name;
    this.password = password;
    this.gendar = gendar;
    this.hasMarried = hasMarried;
  }
 
  public int getAge() {
    return age;
  }
 
  public void setAge(int age) {
    this.age = age;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public String getPassword() {
    return password;
  }
 
  public void setPassword(String password) {
    this.password = password;
  }
 
  public short getGendar() {
    return gendar;
  }
 
  public void setGendar(short gendar) {
    this.gendar = gendar;
  }
 
  public boolean isHasMarried() {
    return hasMarried;
  }
 
  public void setHasMarried(boolean hasMarried) {
    this.hasMarried = hasMarried;
  }
 
  @Override
  public String toString() {
    return "User [age=" + age + ", name=" + name + ", password=" + password + ", gendar=" + gendar + ", hasMarried="
        + hasMarried + "]";
  }
 
  /**
   * (重写对象是否重复方法)
   * 
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object obj) {
 
    if (!(obj instanceof User)) {
      return false;
    }
    User u = (User) obj;
    if (age != u.age || gendar != u.gendar || hasMarried != u.hasMarried || !name.equals(u.name)
        || !password.equals(u.getPassword())) {
      return false;
    }
    return true;
  }
 
  /**
   * (Stream去重有一个先决条件,就是要去重的对象必须实现comparable接口,不能使用比较器)
   * 
   * @see java.lang.Comparable#compareTo(java.lang.Object)
   */
  @Override
  public int compareTo(User o2) {
 
    // 首先比较年龄大小,因为年龄的区分度比较高
    User o1 = this;
    if (o1.age > o2.age) {
      return 1;
    }
    if (o1.age < o2.age) {
      return -1;
    }
    // 如果年龄相同就比较性别,女的排在前面
    if (o1.gendar > o2.gendar) {
      return 1;
    }
    if (o1.gendar < o2.gendar) {
      return -1;
    }
    // 如果性别也一样就比较是否已婚
    if (o1.hasMarried == true && o2.hasMarried == false) {
      // 结婚的排在前面
      return 1;
    }
    if (o1.hasMarried == false && o2.hasMarried == true) {
      // 结婚的排在前面
      return 1;
    }
    // 最后比较姓名,因为字符串比较耗时较长
    if (o1.name.hashCode() > o2.name.hashCode()) {
      return 1;
    }
    if (o1.name.hashCode() < o2.name.hashCode()) {
      return -1;
    }
    return 0;
  }
 
  public List<User> createUserDatas() {
 
    ArrayList<User> userList = new ArrayList<>();
    userList.add(new User(22, "王旭", "123456", (short) 1, true));
    userList.add(new User(22, "王旭", "123456", (short) 1, true));
    userList.add(new User(22, "王旭", "123456", (short) 1, true));
    userList.add(new User(21, "孙萍", "a123456", (short) 2, false));
    userList.add(new User(23, "步传宇", "b123456", (short) 1, false));
    userList.add(new User(18, "蔡明浩", "c123456", (short) 1, true));
    userList.add(new User(17, "郭林杰", "d123456", (short) 1, false));
    userList.add(new User(5, "韩凯", "e123456", (short) 1, true));
    userList.add(new User(22, "韩天琪", "f123456", (short) 2, false));
    userList.add(new User(21, "郝玮", "g123456", (short) 2, false));
    userList.add(new User(19, "胡亚强", "h123456", (short) 1, false));
    userList.add(new User(14, "季恺", "i123456", (short) 1, false));
    userList.add(new User(17, "荆帅", "j123456", (short) 1, true));
    userList.add(new User(16, "姜有琪", "k123456", (short) 1, false));
    return userList;
  }
 
  /**
   * 按照年龄大小进行排序,设计一个Comparator
   * 
   * @return
   */
  public Comparator<User> getAgeComparator() {
 
    return new Comparator<User>() {
      @Override
      public int compare(User o1, User o2) {
        if (o1.age > o2.age)
          return 1;
        if (o1.age < o2.age)
          return -1;
        return 0;
      }
    };
  }
 
  public Comparator<User> getEqualComparator() {
 
    return new Comparator<User>() {
      @Override
      public int compare(User o1, User o2) {
        // 首先比较年龄大小,因为年龄的区分度比较高
        if (o1.age > o2.age) {
          return 1;
        }
        if (o1.age < o2.age) {
          return -1;
        }
        // 如果年龄相同就比较性别,女的排在前面
        if (o1.gendar > o2.gendar) {
          return 1;
        }
        if (o1.gendar < o2.gendar) {
          return -1;
        }
        // 如果性别也一样就比较是否已婚
        if (o1.hasMarried == true && o2.hasMarried == false) {
          // 结婚的排在前面
          return 1;
        }
        if (o1.hasMarried == false && o2.hasMarried == true) {
          // 结婚的排在前面
          return 1;
        }
        // 最后比较姓名,因为字符串比较耗时较长
        if (o1.name.hashCode() > o2.name.hashCode()) {
          return 1;
        }
        if (o1.name.hashCode() < o2.name.hashCode()) {
          return -1;
        }
        return 0;
      }
    };
  }
 
}
package com.zhy.demo.javase.java8.stream;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import com.alibaba.fastjson.JSON;
 
/**
 * @ClassName StreamStudy
 * @Description (Java8 Stream操作总结)
 * @author ZHY
 * @date 2018年8月15日 下午11:17:27
 * @Copyright © 2018【www.zhy.com Inc. All rights reserved.】
 */
public class StreamTest {
 
  private static final Logger LOGGER = LoggerFactory.getLogger(StreamTest.class);
 
  private static User user = new User();
 
  /**
   * 对用户按年龄进行排序
   */
  @Test
  public void testSort1() {
 
    // 传统方式排序
    LOGGER.info("===============传统方式排序===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    Collections.sort(userList1, user.getAgeComparator());
    LOGGER.info("传统方式排序耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    userList1.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    // Java8的方式排序
    LOGGER.info("==============Java8的方式排序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    List<User> sortedUsers = userList2.stream().sorted(user.getAgeComparator()).collect(Collectors.toList());
    LOGGER.info("Java8的方式排序耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    sortedUsers.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
  }
 
  /**
   * 选出年龄最小的三个人
   */
  @Test
  public void testSort2() {
 
    // 传统方式排序
    LOGGER.info("===============传统方式排序===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    Collections.sort(userList1, user.getAgeComparator());
    // 切割出0,1,2这三个子元素
    List<User> userListTopThree1 = userList1.subList(0, 3);
    LOGGER.info("传统方式排序耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    userListTopThree1.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    // Java8的方式排序
    LOGGER.info("==============Java8的方式排序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    List<User> userListTopThree2 = userList2.stream().sorted(user.getAgeComparator()).limit(3)
        .collect(Collectors.toList());
    LOGGER.info("Java8的方式排序耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    userListTopThree2.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
  }
 
  /**
   * 去除重复数据
   */
  @Test
  public void testDisdinct() {
 
    // 传统方式去重
    LOGGER.info("===============传统方式去重===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    int length = userList1.size();
    for (int i = 1; i < length; i++) {
      if (userList1.get(i).equals(userList1.get(i - 1))) {
        userList1.remove(i);
        i--;
        length--;
      }
    }
    LOGGER.info("传统方式去重耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    userList1.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    // Java8的方式去重
    LOGGER.info("==============Java8的方式去重=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    List<User> distinctUserList = userList2.stream().sorted().distinct().collect(Collectors.toList());
    LOGGER.info("Java8的方式去重耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    distinctUserList.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
  }
 
  /**
   * 按条件筛选
   */
  @Test
  public void testFilter() {
 
    // 传统方式按条件筛选
    LOGGER.info("===============传统方式按条件筛选===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    ArrayList<User> result1 = new ArrayList<>();
    for (User user : userList1) {
      if (user.getName().startsWith("韩"))
        result1.add(user);
    }
    LOGGER.info("传统方式按条件筛选耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    result1.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    // Java8的方式按条件筛选
    LOGGER.info("==============Java8的方式按条件筛选=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    List<User> result2 = userList2.stream().filter(user -> user.getName().startsWith("韩"))
        .collect(Collectors.toList());
    LOGGER.info("Java8的方式按条件筛选耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    result2.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    List<User> result3 = userList2.stream().filter(user -> user.getName().startsWith("韩") && user.getGendar() == 2)
        .collect(Collectors.toList());
    List<User> result4 = userList2.stream().filter(user -> user.getName().startsWith("韩"))
        .filter(user -> user.getGendar() == 2).collect(Collectors.toList());
    List<User> result5 = userList2.stream().filter(user -> user.getGendar() == 2)
        .filter(user -> user.getName().startsWith("韩")).collect(Collectors.toList());
    LOGGER.info("result3 ==> {}", JSON.toJSONString(result3, true));
    LOGGER.info("result4 ==> {}", JSON.toJSONString(result4, true));
    LOGGER.info("result5 ==> {}", JSON.toJSONString(result5, true));
  }
 
  /**
   * 只列出所有人的名字和婚姻状况
   */
  @Test
  public void testMap() {
 
    // 传统方式
    LOGGER.info("===============传统方式===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    ArrayList<String> result1 = new ArrayList<String>();
    for (User user : userList1) {
      result1.add(user.getName() + ":".concat(user.isHasMarried() ? "已婚" : "未婚"));
    }
    LOGGER.info("传统方式耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    result1.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
    // Java8的方式
    LOGGER.info("==============Java8的方式序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    List<String> result2 = userList2.stream()
        .map(user -> user.getName() + ":".concat(user.isHasMarried() ? "已婚" : "未婚"))
        .collect(Collectors.toList());
    LOGGER.info("Java8的方式耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    result2.stream().forEach(user -> {
      LOGGER.info(user.toString());
    });
  }
 
  /**
   * 判断当前数组是否包含某些特定元素
   */
  @Test
  public void testAnyMatch() {
 
    // 传统方式
    LOGGER.info("===============传统方式===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    boolean isChild1 = false;
    for (User user : userList1) {
      if (user.getAge() < 18) {
        isChild1 = true;
        break;
      }
    }
    LOGGER.info("传统方式耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    LOGGER.info("isChild1 ==> {}", isChild1);
    // Java8的方式
    LOGGER.info("==============Java8的方式序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    boolean isChild2 = userList2.stream().anyMatch(user -> user.getAge() < 18);
    LOGGER.info("Java8的方式耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    LOGGER.info("isChild2 ==> {}", isChild2);
  }
 
  /**
   * 确认所有元素均满足某一条件
   */
  @Test
  public void testAllMatch() {
 
    // 传统方式
    LOGGER.info("===============传统方式===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    boolean allMarried1 = true;
    for (User user : userList1) {
      if (!user.isHasMarried()) {
        allMarried1 = false;
        break;
      }
    }
    LOGGER.info("传统方式耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    LOGGER.info("allMarried1 ==> {}", allMarried1);
    // Java8的方式
    LOGGER.info("==============Java8的方式序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    boolean allMarried2 = userList2.stream().allMatch(user -> user.isHasMarried());
    LOGGER.info("Java8的方式耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    LOGGER.info("allMarried2 ==> {}", allMarried2);
  }
 
  /**
   * 求和求平均值
   */
  @Test
  public void testSum() {
 
    // 传统方式
    LOGGER.info("===============传统方式===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    int sum1 = 0;
    for (User user : userList1) {
      sum1 += user.getAge();
    }
    LOGGER.info("传统方式耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    LOGGER.info("sum ==> {}", sum1);
    // Java8的方式
    LOGGER.info("==============Java8的方式序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    int sum2 = userList2.stream().mapToInt(user -> user.getAge()).sum();
    LOGGER.info("Java8的方式耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    LOGGER.info("sum2 ==> {}", sum2);
  }
 
  /**
   * 分组
   */
  @Test
  public void testGroupingBy() {
 
    // 传统方式
    LOGGER.info("===============传统方式===============");
    List<User> userList1 = user.createUserDatas();
    long time1 = System.currentTimeMillis();
    Map<Integer, List<User>> group1 = new HashMap<>();
    for (User user : userList1) {
      List<User> list = group1.get(user.getAge());
      if (list == null) {
        list = new ArrayList<User>();
        group1.put(user.getAge(), list);
      }
      list.add(user);
    }
    LOGGER.info("传统方式耗时 ==> {} (ms)", System.currentTimeMillis() - time1);
    LOGGER.info("group1 ==> {}", JSON.toJSONString(group1), true);
    // Java8的方式
    LOGGER.info("==============Java8的方式序=============");
    List<User> userList2 = user.createUserDatas();
    long time2 = System.currentTimeMillis();
    Map<Integer, List<User>> group2 = userList2.stream().collect(Collectors.groupingBy(t -> t.getAge()));
    // 如果想按是否结婚分组,也就是key变成bool,那就应该这么写
    // Map<Boolean,List<User>> group =
    // users.stream().collect(Collectors.partitioningBy(t->t.hasMarried));
    LOGGER.info("Java8的方式耗时 ==> {} (ms)", System.currentTimeMillis() - time2);
    LOGGER.info("group2 ==> {}", JSON.toJSONString(group2), true);
  }
 
  /**
   * 链式操作
   */
  @Test
  public void testLinkOperation() {
 
    LOGGER.info("==============Java8链式操作=============");
    List<User> userList = user.createUserDatas();
    long time = System.currentTimeMillis();
    userList.stream().filter(t -> t.getGendar() == 2).map(t -> t.getName()).forEach(System.out::println);
    LOGGER.info("Java8链式操作耗时 ==> {} (ms)", System.currentTimeMillis() - time);
  }
 
}

大家最好把上面代码复制到便一起上试试!!!

原文发布于微信公众号 - Java研发军团(ityuancheng)

原文发表时间:2018-11-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券