Stream流
- Stream流只能用一次,所以一般不用返回Stream类接收,直接写为链式编程的形式
- Stream.of()可以传递零散的数组,也可以传递引用类型的数组,不能传递基本数据类型,否则会把真个数组当作一个元素,输出一个地址值。
- 修改流中的数据不会影响原来集合、数组中的数据。
创建Stream:
//单列集合
//default Stream<E> stream() Collection中的默认方法
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aa","bb","cc","dd");
list.stream().forEach(s-> System.out.println(s));
//双列集合 无法直接使用
HashMap<String,Integer> hm = new HashMap<>();
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
hm.keySet().stream().forEach(s-> System.out.println(s));
hm.entrySet().stream().forEach(s-> System.out.println(s));
//数组
//public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
int[] arr = {1,2,3,4,5};//基本数据类型
Arrays.stream(arr).forEach(n-> System.out.print(n));
System.out.println();
String[] arr2 = {"aa","bb","cc","dd"};//引用数据类型
Arrays.stream(arr2).forEach(s-> System.out.println(s));
//零散数据(必须是同种数据类型)
// public static<T> Stream<T> of(T... values) Stream接口中的静态方法
Stream.of(1,2,3,4,5).forEach(n-> System.out.println(n));
Stream.of("aa","bb","cc","dd").forEach(s-> System.out.println(s));
Stream的中间方法
过滤:
//Stream<T> filter(Predicate<? super T>predicate)
//过滤出长度大于2的字符串
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"黄景瑜","罗人友","黄轩","黄轩","吴磊","许凯","刘昊然");
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() > 2;
}
}).forEach(s-> System.out.println(s));
//lambda表达式
list.stream().filter(s -> s.length() > 2).forEach(s-> System.out.println(s));
获取前几个元素:
//获取前三个元素
list.stream().limit(3).forEach(s-> System.out.print(s));
跳过前几个元素
//跳过前三个元素
list.stream().skip(3).forEach(s-> System.out.print(s));
元素去重
依赖HashCode和equals方法
//Stream<T> distinct()
list.stream().distinct().forEach(s-> System.out.print(s + " "));
合并两个Stream流
//static<T> Stream<T> concat(Stream a, Stream b)
Stream.concat(list.stream(),list.stream()).forEach(s-> System.out.print(s + " "));
转换流中的数据类型
//Stream<R> map(Function<T, R> mapper)
//由T转为R
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"黄景瑜-29","罗人友-30","黄轩-34","吴磊-23","许凯-28","刘昊然-24");
list1.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");//split("-")奖“-”前的放到String数组的0索引位置,“-”后的放入1索引位置
String age = arr[1];
return Integer.parseInt(age);
}
}).forEach(s-> System.out.println(s));
//lambda形式
list1.stream().map(s-> Integer.parseInt(s.split("-")[1])).forEach(s->System.out.print(s+“ ”));
//输出:29 30 34 23 28 24
Stream流的终结方法
即该方法的返回不能再计=继续调用其他Stream流中的方法
forEach()
count()
collect()// 将Stream流收集到集合(LIst,Set,Map)
collect(Collector.toList())
collect(Collector.toSet())
collect(Collector.toMap())
方法引用
把已经有的方法拿来用,当作函数式接口中抽象方法的方法体。被引用的方法可以是Java已经写好的,也可以是自己写的。
要求
- 引用处必须是函数式接口(FunctionInterface)
- 被引用的方法必须已经存在
- 被引用方法的形参和返回值须要和抽象方法保持一致
- 被引用方法的功能要满足当前需求
“::”是方法引用符号
类名::方法名()
引用静态方法
类名::静态方法
引用成员方法
格式:对象::成员方法
本类:this::方法名(引用处不能是静态方法)
父类:super::方法名(引用处不能是静态方法)
- 特例:使用类名引用成员方法
类名::成员方法
特殊规则:- 引用处必须是函数式接口(FunctionInterface)
- 被引用的方法必须已经存在
- 被引用方法的形参需要和抽象方法的第二个形参到最后一个形参保持一致,返回值须要和抽象方法保持一致(抽象方法第一个形参是什么类,就只能引用这个类的方法)
- 被引用方法的功能要满足当前需求
引用构造方法
类名::new
前提是要有和引用处函数式接口的形参一样的构造方法
- 特例:引用数组的构造方法
数据类型[] :: new
数据类型和抽象方法的返回值一样
举例:
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
list.add(new Student("wangwu",25));
// list.stream().map(new Function<Student, String>() {
// @Override
// public String apply(Student student) {
//
// return student.getName();
// }
// }).;
String[] array = list.stream().map(Student::getName).toArray(String[]::new);
System.out.println(Arrays.toString(array));