一、流的操作
生成流的操作
通过数据源(集合、数组等)生成流
如,list.stream()
中间操作
一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用
如,filter(),其操作完成之后还是一个stream流
终结操作
一个流只能有一个终结操作,当这个操作执行后,流就被使用"光"了,无法再被操作。所以这必定是流的最后一个操作forEach()
forEach()
二、Stream流的生成方式
Stream流常见的生成方式有三种
Colletion体系的集合可以使用默认方法stream()生成流
default Stream <E> stream()
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<>();
Stream<String> setStream = set.stream();
Map体系的集合间接的生成流
Map<String,Integer> map = new HashMap<>();
// 这就是间接的获取键的stream流:map.keySet() 得到键的set集合,再通过键的set集合获取到流,
Stream<String> keyStream = map.keySet().stream();
// 间接的获取值的stream流
Stream<Integer> valueStream = map.values().stream();
// 键值对对象所对应的流
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArray = {"hello","world","java"};
Stream<String> strArrayStream = Stream.of(strArray);
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
Stream<Integer> intStream = Stream.of(10, 20, 30);
三、Stream流常见中间操作方法
3.1 中间操作之filter(Predicate predicate)
Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法 boolean test(T t) : 对给定的参数进行判断,返回一个布尔值
需求:把list集合中以张开头的元素在控制台输出
ArrayList<String> list = new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
// 需求:把list集合中以张开头的元素在控制台输出
// filter()需要一个函数式接口,在这里我们可以写一个lambda表达式
list.stream().filter( (String s) ->{
return s.startsWith("张");
} ).forEach(System.out::println);
其中我们的lambda表达式可以简写成下面的形式
list.stream().filter(s->s.startsWith("张")).forEach(System.out::println);
需求:把list集合中长度为3的元素在控制台输出
list.stream().filter(s->s.length()==3).forEach(System.out::println);
需求: 把list集合中以张开头的,长度为3的元素在控制台输出
list.stream()
.filter(s->s.startsWith("张"))
.filter(s->s.length()==3)
.forEach(System.out::println);
3.2 中间操作之limit&skip
Stream<T> limit(long maxSize):返回流中的元素组成的流,截取前指定参数个数的数据
Stream<T> skip(long n): 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
需求:取前3个数据在控制台输出
list.stream()
.limit(3)
.forEach(System.out::println);
需求:跳过3个元素,把剩下的元素在控制台输出
list.stream()
.skip(3)
.forEach(System.out::println);
需求:跳过2个元素,把剩下的元素中前两个在控制台输出
list.stream()
.skip(2)
.limit(2)
.forEach(System.out::println);
3.3 中间操作之concat&distinct()
static<T> Stream<T> concat(Stream a,Stream b):合并a和b两个流为一个流(静态方法)
Stream<T> distinct():返回由该流的不同元素(根据Object.equals(Object))组成的流
需求:取前四个数据组成一个流
Stream<String> s1 = list.stream().limit(4);
需求:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
需求: 合并需求1和需求2得到的流,并把结果在控制台输出
Stream.concat(s1, s2).forEach(System.out::println);
需求: 合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(System.out::println);
3.4 中间操作之sorted
Stream<T> sorted:返回由此流的元素组成的流,根据自然顺序排序
Stream<T> sorted(Compatator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序
需求:按照字母顺序把数据在控制台输出
ArrayList<String> list = new ArrayList<>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("liuyan");
list.add("zhangmin");
list.add("zhangwuji");
list.stream().sorted().forEach(System.out::println);
需求:按照字符串长度把数据在控制台输出
list.stream()
.sorted((s1,s2)->{
int num = s1.length()-s2.length();
int num2 = num ==0 ? s1.compareTo(s2) : num;
return num2;
})
.forEach(System.out::println);
3.5 中间操作之map&mapToInt
<R> Stream<R> map(Fucntion mapper):返回由给定函数应用于此流的元素的结果组成的流
Function接口中的方法 R apply(T t)
IntStream map ToInt(ToIntFuction mapper):返回一个IntStream其中包含将给定函数应用于此流的元素的结果
IntStream:表示原始int流
ToIntUFunction接口中的方法 int applyAsInt(T value)
需求: 将集合中的字符串数据转换为整数之后再控制台输出
ArrayList<String> list = new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");
list.add("40");
list.add("50");
list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println);
或者
list.stream().map(Integer::parseInt).forEach(System.out::println);
或者 mapToInt也可以
list.stream()
.mapToInt(Integer::parseInt)
.forEach(System.out::println);
结果:
IntStream也是一个接口,支持顺序和并行聚合操作的原始int值元素序列,其有个方法是 int sum() 返回流中元素的总和
注意:sum方法是IntStream接口中的,而Stream接口中是没有的
int sum = list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(sum);
四、Stream流常见终结操作方法
void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t): 对给定的参数执行此操作
我们前面指定的就是再控制台输出我们的数据
long count():返回此流中元素数
需求:把集合中的元素在控制台输出
ArrayList<String> list = new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
list.stream().forEach(System.out::println);
需求: 统计集合中有几个以张开头的元素,并把统计结果输出
long count = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(count);
五、Stream流的练习
public class Actor {
private String name;
public Actor(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ArrayList<String> manList = new ArrayList<>();
manList.add("周润发");
manList.add("成龙");
manList.add("刘德华");
manList.add("吴京");
manList.add("周星驰");
manList.add("李连杰");
ArrayList<String> womanList = new ArrayList<>();
womanList.add("林心如");
womanList.add("张曼玉");
womanList.add("林青霞");
womanList.add("柳岩");
womanList.add("林志玲");
womanList.add("王祖贤");
现在有两个ArrayList集合,分别存储6名男演员和6名女演员名称,要求完成如下的操作
男演员只要名字为3个字的前三人
Stream<String> manStream = manList.stream()
.filter(s -> s.length() == 3)
.limit(3);
女演员只要姓林的,并且不要第一个
Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
把过滤后的男演员姓名和女演员姓名合并到一起
Stream<String> stream = Stream.concat(manStream, womanStream);
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带构造方法,以及成员变量对应的get/set方法
stream.map(Actor::new).forEach(System.out::println);
我们没有重写toString方法
stream.map(Actor::new).forEach( p-> System.out.println(p.getName()));
六、Stream流的收集操作
对数据使用stream流的方式操作完毕后,想把流中的数据收集到集合中
Stream流的收集方法
R collect(Collector collector)
<R,A> R collect(Collector<? super T,A,R> collector)
其中Collector<? super T,A,R>是一个接口
Collectors是一个工具类,实现各种有用的还原操作的Collector,例如将元素累积到集合中,根据各种标准汇总元素等
工具类Collectors提供了具体的收集方式
public static <T> Collector toList(): 把元素收集到List集合中
ArrayList<String> list = new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
// 需求1:得到名字为3个字的流
Stream<String> listStream = list.stream().filter(s -> s.length() == 3);
// 需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
List<String> names = listStream.collect(Collectors.toList());
for(String name :names){
System.out.println(name);
}
}
public static <T> Collector toSet(): 把元素收集到Set集合中
Set<Integer> set = new HashSet<>();
set.add(10);
set.add(20);
set.add(30);
set.add(33);
set.add(35);
// 需求: 大于25
Stream<Integer> setStream = set.stream().filter(are -> are > 25);
// 需求:把使用Stream流操作完毕的数据收集到Set集合中并遍历
Set<Integer> ages = setStream.collect(Collectors.toSet());
for(Integer age :ages)
System.out.println(age);
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
String[] strArray = {"林青霞,30","张曼玉,35","王祖贤,33","柳岩,25"};
// 需求:得到字符串中年龄数据大于28的流
Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);
// 需求:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作为键,年龄作为值
Map<String, Integer> map = arrayStream.collect(Collectors.toMap( s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1]) ) );
Set<String> keySet = map.keySet();
for(String key: keySet){
System.out.println(key+","+map.get(key));
}