Stream流把真正的函数式编程风格引入到java中
案例:需求:
创建集合,存储多个字符串元素;把集合中“张”开头的字符串存储到另外的集合中;把“张”开头的集合中的长度大于3的元素存储到另外集合中;遍历上一步得到的集合。
public class StreamDemo {
public static void main(String[] args) {
ArrayList array = new ArrayList();
array.add("林俊杰");
array.add("张信哲");
array.add("王一博");
array.add("许嵩");
array.add("张杰");
array.add("张艺兴");
ArrayList zhang = new ArrayList();
for(String s:array){
if(s.startsWith("张")){
zhang.add(s);
}
}
System.out.println( "zhang集合:"+zhang);
ArrayList zhang3 = new ArrayList();
for(String s :zhang){
if(s.length() == 3){
zhang3.add(s);
}
}
System.out.println("zhang3集合:" + zhang3);
System.out.println("-----------");
// 使用stream流实现
array.stream().filter(s->s.startsWith("张")).filter(s-> s.length() == 3).forEach(s-> System.out.println(s));
* 注意:
* 意思:array.stream生成流、过滤张、过滤长度为3、forEach逐一打印
// 使用引用类方法简化
System.out.println("简化");
array.stream().filter(s -> s.startsWith("张")).filter(s -> s.length()==3).forEach(System.out::println);
}
}
Stream流的生成方式
Stream的使用:
1 生成流 通过数据源(集合、数组等)生成流 list.stream() 2 中间操作 一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用。 filter() 3 终结操作 一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。 forEach()
Stream流的常见生成方式:
1 Collection体系的集合可以使用默认方法stream()生成流 default Stream< E > stream() 2 Map 体系的集合间接的生成流 可以使用方法keySet方法、values方法、entrySet方法 3 数组可以通过Stream接口的静态方法of(T...values)生成流 其中静态方法of(T....values)是可变参数。 * Stream.of(T...values)
代码:
public class StreamDemo1 {
public static void main(String[] args) {
// Collection体系的集合可以使用默认方法stream()生成流
// List 和 Set 是Collection的儿子
List list = new ArrayList();
Stream listStream = list.stream();
Set set = new HashSet();
Stream setStream = set.stream();
// Map 体系的集合间接的生成流
Map map = new HashMap();
Stream keyStrem = map.keySet().stream();
// map.ksySet得到是 键的集合,集合通过stream方法可以得到stream流
Stream valueStream = map.values().stream();
// map.values 得到 值的集合,集合通过stream方法可以得到stream流
Stream> kvStream = map.entrySet().stream();
// map.entrySet 得到键值对 对象的集合
// 数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArray = {"you","are","my","pretty","sunshine"};
Stream strArray1 = Stream.of(strArray);
Stream strStream2 = Stream.of("hello", "world");
Stream integerStream = Stream.of(10, 20, 30);
}
}
Stream流的中间操作方式
中间操作方法:
| 方法名 | 说明 |
|---|---|
| Stream < T > filter(Predicate predicate) | 用于对流中的数据进行过滤 Predicate接口中的方法,boolean test(T t):对给定的参数进行操作,返回一个布尔值 |
| Stream< T > limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
| Stream< T > skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
| static < T > Stream < T > concat(Stream a,Stream b) | 合并a和b两个流为一个流 |
| Stream< T > distinct() | 返回由该流的不同元素(Object.equals(Object))组成的流 |
| Stream< T > sorted() | 返回由此流的元素组成的流,根据自然顺序排序 |
| Stream< T > sorted(Comparator comparator | 返回由该留的元素组成的流,根据提供的Comparator进行排序 Comparator接口中的方法 int compare(T o1,T o2) |
| < R > Stream < R > map(Function mapper) | 返回由给定函数应用于此流的元素的结果组成的流 Function接口中的方法 R apply(T t) |
| IntStream mapToInt(ToIntFunction mapper) | 返回一个IntStream,其中包含将给定函数应用于此流的元素的结果 IntStream 表示原始int流ToIntFunction接口中的方法 int applyAsInt(T value) 其中IntStream接口中有方法int sum() 返回此流中元素的总和 |
案例1:filter
public class StreamDemo2 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
// 需求1:把list集合中的以张开头的元素在控制台输出
// 流生成方式1 Collection集合中静态方法Stream方法
list.stream().filter((String s) -> s.startsWith("张")).forEach((String s)-> System.out.println(s));
// 省略 引用类的方法 对象::实例方法
list.stream().filter(s->s.startsWith("张")).forEach(System.out::println);
System.out.println("-----------------");
// 需求2:把list集合中长度为3的元素在控制台输出
// 对象::实例方法
list.stream().filter(s->s.length() == 3).forEach(System.out::println);
System.out.println("------");
// 需求3:把list集合中以张开头,长度为3的元素在控制台输出
list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(System.out::println);
}
}
案例2:limit skip
public class StreamDemo3 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
// 需求1:取前三个数据在控制台输出
list.stream().limit(3).forEach(System.out::println);
// 输出结果是:林俊杰 张信哲 王一博
System.out.println("-------");
// 需求2:跳过3个数据,把剩下的元素在控制台输出
list.stream().skip(3).forEach(System.out::println);
// 输出结果是:胡夏 张杰 张艺兴
System.out.println("-----");
// 需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
list.stream().skip(2).limit(2).forEach(System.out::println);
// 输出结果:王一博 胡夏
}
}
案例3:dictinct concat
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
// 需求1:取前4个数组组成一个流
Stream s1 = list.stream().limit(4);
// 需求2:跳过2个数据组成一个流
Stream s2 = list.stream().skip(2);
// 需求3:合并需求1和需求2得到的流,并把结果在控制台输出
// Stream.concat(s1, s2).forEach(System.out::println);
// 需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
// 输出:林俊杰 张信哲 王一博 胡夏 王一博 胡夏 张杰 张艺兴
System.out.println("---------");
Stream.concat(s1, s2).distinct().forEach(System.out::println);
// 输出结果:林俊杰 张信哲 王一博 胡夏 张杰 张艺兴
// 同时执行两个Stream.concat 会报错。IllegalStateException: stream has already been operated upon or closed
// 流只能运行(调用中间或终端流操作)一次。
}
}
案例4:sorted
public class StreamDemo5 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("liuyan");
list.add("zhangmin");
list.add("zhagnwuji");
// 需求1:按照字母顺序把数据在控制台输出
// list.stream().sorted().forEach(System.out::println);
// 需求2:按照字符串长度把数据在控制台输出
// 匿名内部类
// list.stream().sorted(new Comparator() {
// @Override
// public int compare(String s1, String s2) {
// return s1.length() - s2.length();
// }
// }).forEach(System.out::println);
// 输出结果有问题:liuyan
//zhangmin
//zhagnwuji
//linqingxia
//zhangmanyu
//wangzuxian
//其中 后三个没有按照字母顺序排 而是按照添加顺序
// Lambda表达式
// list.stream().sorted((s1,s2)->s1.length()-s2.length()).forEach(System.out::println);
// 长度相同 按照自然顺序排
list.stream().sorted((s1,s2)->{
int sum = s1.length()-s2.length();
int sum2 = sum == 0?s1.compareTo(s2):sum;
return sum2;
}).forEach(System.out::println);
// 输出结果:
}
}
案例5:map mapToInt
public class StreamDemo6 {
public static void main(String[] args) {
ArrayList array = new ArrayList();
array.add("10");
array.add("20");
array.add("30");
array.add("40");
array.add("50");
// 需求:将集合中的字符串数据转化为整数之后在控制台输出
// array.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
// array.stream().map(Integer::parseInt).forEach(System.out::println);
// 方法引用 分别是 类的方法(类名::静态方法)、对象的实例方法(对象的成员方法)
// array.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
// mapToInt方法的返回值类型是 IntStream 其中有个int sum()方法 返回此流中元素的总和。
int result = array.stream().mapToInt(Integer::parseInt).sum();
System.out.println(result);
// 输出结果150
}
}
Stream流的常见终结操作方法
| 方法名 | 说明 |
|---|---|
| viod forEach(Consumer action) | 对此流的每个元素执行操作 Consumer接口中的方法 void accept(T t)对给定的参数执行此操作 |
| long count() | 返回此流中的元素个数 |
案例:
public class StreamDemo7 {
public static void main(String[] args) {
ArrayList list= new ArrayList();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("刘维");
list.add("张杰");
list.add("张艺兴");
// 需求1:把集合中的元素在控制台输出
// list.stream().forEach(System.out::println);
// 需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
long result = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(result);
// 输出结果是3
}
}
Stream流练习
需求:
有两个ArrayList集合,分别存储6名男演员和6名女演员名称,完成如下操作:
1 男演员只要名字为三个字的前三个人
2 女演员只要姓林的,并且不要第一个人
3 把过滤后的男演员名字和女演员名字合并在一起
4 把上一个步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor,有一个成员变量,一个带参构造方法,以为其对应的get/set方法
public class StreamDemo {
public static void main(String[] args) {
// 创建集合
ArrayList manList = new ArrayList();
manList.add("周润发");
manList.add("成龙");
manList.add("刘德华");
manList.add("吴京");
manList.add("周星驰");
manList.add("李连杰");
ArrayList womanList = new ArrayList();
womanList.add("林心如");
womanList.add("张嘉倪");
womanList.add("林黛玉");
womanList.add("柳岩");
womanList.add("林志玲");
womanList.add("王祖贤");
// 1 男演员只要名字为三个字的前三个人
Stream manStream = manList.stream().filter(s->s.length() ==3).limit(3);
// 2 女演员只要姓林的,并且不要第一个人
Stream womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
// 3 把过滤后的男演员名字和女演员名字合并在一起
Stream conStream = Stream.concat(manStream, womanStream);
// 4 把上一个步操作后的元素作为构造方法的参数创建演员对象,遍历数据
// conStream.map(Actor::new).forEach(System.out::println);
// 引用方法是 引用构造器 = 类::构造方法
conStream.map(Actor::new).forEach(p-> System.out.println(p.getName()));
}
}
Stream流的收集操作
对数据使用Stream流的方式后,把流中的数据收集到集合中,收集方法是:R collect(Collector collector)参数Collector 是一个接口interface,interface Collector< T,A,R >工具类Collectors类实现了各种有用的还原操作的CollectorCollector类提供了具体的收集方法:
| 方法名 | 说明 |
|---|---|
| public static < T > Collector toList() | 把元素收集到List集合中 |
| public static < T > Collector toSet() | 把元素收集到Set集合中 |
| public static < T > Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
案例:
public class test7 {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("刘维");
// // 需求1:得到名字为三个字的流
// Stream stringList = list.stream().filter(s -> s.length() == 3);
// // 需求2:把使用Stream流操作完毕的数据收集到List集合中
// List names = stringList.collect(Collectors.toList());
// for(String name:names ){
// System.out.println(name);
// }
Set set = new HashSet();
set.add(10);
set.add(20);
set.add(30);
set.add(33);
set.add(35);
// // 需求3:年龄大于25的流
// Stream integerStream = set.stream().filter(a -> a > 25);
// // 需求4:把使用Stream流操作完毕的数据收集到Set集合中
// Set ages = integerStream.collect(Collectors.toSet());
// for(Integer age : ages){
// System.out.println(age);
// }
String[] strArray = {"林俊杰,30","张信哲,35","王一博,33","刘维,25"};
// 需求5:字符串中年龄大于28的流
Stream ageStream = Stream.of(strArray).filter(s ->
Integer.parseInt(s.split(",")[1]) >28 );
// 需求6:把使用Stream流操作完毕的数据收集到Map集合中,并遍历
Map map = ageStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
Set keySet = map.keySet();
for(String key:keySet){
Integer value = map.get(key);
System.out.println("姓名:" + value + ", " + "年龄:" + key);
}
}
}



