Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
在 Java 8 中, 集合接口有两个方法来生成流:
// 为集合创建串行流 Stream<String> stream = list.stream(); // 为集合创建并行流 Stream<String> stream = list.parallelStream();
public class Demo01 { public static void main(String[] args) { //创建一个集合,存储多个字符串元素。 List<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); list.add("张敏"); list.add("张无忌"); /* filter()方法是中间操作,中间操作都用lambda表达式。 */ //需求1:把list集合中以“张”开头的元素在控制台输出。 System.out.println("======需求1====="); list.stream().filter(x -> x.startsWith("张")).forEach(System.out::println); //需求2:把list集合中长度为3的元素在控制台输出。 System.out.println("======需求2====="); list.stream().filter(x -> x.length() == 3).forEach(System.out::println); //需求3:把list集合中以“张”开头的,长度为3的元素在控制台输出。 System.out.println("======需求3====="); //在一个过滤器中要满足两个条件。 list.stream().filter(x -> x.startsWith("张") && x.length() == 3).forEach(System.out::println); System.out.println("-----"); //用两个过滤器,先过滤出以“张”开头的元素,再过滤出长度为3的元素。 list.stream().filter(x -> x.startsWith("张")).filter(x -> x.length() == 3).forEach(System.out::println); } }
理解stream流的时候,可以顺便复习复习lambda表达式。
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)
/* 中间操作 限制:limit() 跳过:skip() */ public class Demo02 { public static void main(String[] args) { //创建一个集合,存储多个字符串元素。 List<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); list.add("张敏"); list.add("张无忌"); //需求1:取前3个数据在控制台输出。 System.out.println("======需求1======"); list.stream().limit(3).forEach(System.out::println); //需求2:跳过3个元素,把剩下的元素在控制台输出。 System.out.println("=====需求2======="); list.stream().skip(3).forEach(System.out::println); //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出。 System.out.println("=====需求3======"); //先用一个skip(2)跳过前两个元素,在剩下的元素中用limit(2)取前两个元素并输出。 list.stream().skip(2).limit(2).forEach(System.out::println); } }
/* 中间操作 合并流:concat()------这是一个静态方法。Stream.concat() 去重:distinct() */ public class Demo03 { public static void main(String[] args) { //创建一个集合,存储多个字符串元素。 List<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); list.add("张敏"); list.add("张无忌"); //需求1:取前4个数据组成一个流。 Stream<String> stream1 = list.stream().limit(4); //需求2:跳过2个数据组成一个流。 Stream<String> stream2 = list.stream().skip(2); //需求3:合并需求1和需求2得到的流,并把结果在控制台输出。 //合并流的方法concat()是一个静态方法。 Stream.concat(stream1, stream2).forEach(System.out::println); //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复。 Stream.concat(stream1, stream2).distinct().forEach(System.out::println); } }
/* 中间操作 自然排序:sorted() 用比较器比较排序:sorted(Comparator comparator) */ public class Demo04 { public static void main(String[] args) { //创建一个集合,存储多个字符串元素。 List<String> list = new ArrayList<>(); list.add("linqingxia"); list.add("zhangmanyu"); list.add("wangzuxian"); list.add("liuyan"); list.add("zhangming"); list.add("zhangwuji"); //需求1:按照字母顺序把数据在控制台输出。 System.out.println("====需求1===="); list.stream().sorted().forEach(System.out::println); //需求2:按照字符串长度把数据在控制台输出。 System.out.println("====需求2===="); //前面-后面:从小到大 后面-前面:从大到小 list.stream().sorted((s1, s2) -> s1.length() - s2.length()).forEach(System.out::println); //需求3:先按照长度,再按照字母顺序排序。 System.out.println("====需求3===="); list.stream().sorted((s1, s2) -> { int sort1 = s1.length() - s2.length(); int sort2 = sort1 == 0 ? s1.compareTo(s2) : sort1; return sort2; }).forEach(System.out::println); } }
/* 中间操作 返回此流元素组成的流:map() IntSteam mapToInt() 返回一个IntSteam类型的结果 */ public class Demo05 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("10"); list.add("20"); list.add("30"); list.add("40"); list.add("50"); //需求:将集合中的字符串数据转换为整数之后在控制台输出。 System.out.println("====需求1===="); list.stream().map(x->Integer.parseInt(x)).forEach(System.out::println); //以上方法可以改进。 System.out.println("====需求1改进===="); list.stream().map(Integer::parseInt).forEach(System.out::println); //以上方法还可以改进。 System.out.println("====需求1再改进===="); //用第3个 list.stream().mapToInt(Integer::parseInt).forEach(System.out::println); //求和 int sum = list.stream().mapToInt(Integer::parseInt).sum(); System.out.println("求和:" + sum); } }
/* 终结操作 输出:forEach() 返回流中的元素数:count() */ public class Demo06 { public static void main(String[] args) { //创建一个集合,存储多个字符串元素。 List<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); list.add("张敏"); list.add("张无忌"); //需求1:把集合中的元素在控制台输出。 System.out.println("====需求1===="); list.stream().forEach(System.out::println); //需求2:统计集合中有几个以“张”开头的元素,并把统计结果在控制台输出。 System.out.println("====需求2===="); long count = list.stream().filter(x -> x.startsWith("张")).count(); System.out.println(count); } }
map只是把一个新的流转换为一个新的流,而collect的把流转换为集合。
/* Stream流的收集操作 */ public class Demo08 { public static void main(String[] args) { //创建List集合对象 List<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("柳岩"); //需求1:得到名字为3个字的流 Stream<String> stream = list.stream().filter(x -> x.length() == 3); //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历。 List<String> collectList = stream.collect(Collectors.toList()); System.out.println("=====List====="); for (String string : collectList) { System.out.println(string); } //创建Set集合对象。 Set<Integer> set = new HashSet<>(); set.add(10); set.add(20); set.add(30); set.add(40); //需求3:得到大于25的流 Stream<Integer> integerStream = set.stream().filter(x -> x > 25); //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历。 Set<Integer> collectSet = integerStream.collect(Collectors.toSet()); System.out.println("=====Set====="); //Set集合是无序的,输出无序。 for (Integer integer : collectSet) { System.out.println(integer); } //定义一个字符串数组。 String string[] = {"林青霞,1", "张曼玉,2", "王祖贤,3", "柳岩,4"}; //需求5:得到字符串中数据大于2的流。 Stream<String> stringStream = Stream.of(string).filter(x -> Integer.parseInt(x.split(",")[1]) > 2); //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,序号作值。 Map<String, Integer> integerMap = stringStream.collect(Collectors.toMap(x -> x.split(",")[0], x -> Integer.parseInt(x.split(",")[1]))); Set<String> ketSet = integerMap.keySet(); System.out.println("=====Map====="); for (String str : ketSet) { Integer value = integerMap.get(str); System.out.println(str + "=" + value); } } }
/* Stream流的练习 现在有两个 ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作 1.男演员只要名字为3个字的前三人 2.女演员只要姓林的,井且不要第一个 3.把过滤后的男演员姓名和女演员姓名合并到一起 4.把上一步操作后的元素作为构造方法的参数创建演员对象遍历数据 演员类Actor已经提供,里面有一个成员变量,一个带参造方法,以及成员变量对应的 get/set方法 */ public class Demo01 { public static void main(String[] args) { //男演员集合 List<String> manList = new ArrayList<>(); manList.add("周润发"); manList.add("成龙"); manList.add("刘德华"); manList.add("吴京"); manList.add("周星驰"); manList.add("李连杰"); //女演员集合 List<String> womanList = new ArrayList<>(); womanList.add("林心如"); womanList.add("张曼玉"); womanList.add("林青霞"); womanList.add("柳岩"); womanList.add("林志玲"); womanList.add("王祖贤"); System.out.println("================方法1================"); Stream<String> manListStream = manList.stream().filter(name -> name.length() == 3).limit(3); Stream<String> womanListStream = womanList.stream().filter(name -> name.startsWith("林")).skip(1); Stream<String> concatStream = Stream.concat(manListStream, womanListStream); concatStream.map(name -> new Actor(name)).forEach(System.out::println); // concatStream.map(Actor::new).forEach(System.out::println); System.out.println("================方法2================"); Stream.concat(manList.stream().filter(x -> x.length() == 3).limit(3) , womanList.stream().filter(x -> x.startsWith("林")).skip(1)) .map(Actor::new) .forEach(System.out::println); } } class Actor { private String name; public Actor() { } public Actor(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Actor{" + "name='" + name + '\'' + '}'; } }
参考资料:Java 8 Stream | 菜鸟教程 (runoob.com)