Java学习day08--方法引用和Stream流
方法引用和Stream流
1).流思想:类似于“迭代器”,对“集合元素”进行多次的筛选、过滤、统计用的。
2).流的工作方式:每个操作后,这个流对象就成为垃圾,等待被回收;但这个操作的方法通常会返回一个新流--每个“流对象”都是一次性的。类似于:流水线。
3).Stream流中大量运用lambda表达式,对于某些lambda表达式而言,可以利用方法引用替换lambda表达式,从而再次简化代码。
4).方法引用是指,当我们要编写一个Lambda表达式时,发现已经有一个现有的方法已经实现了我们在Lambda中要实现的功能,这时就可以引用这个已写好的方法,来代替我们的Lambda表达式。
方法引用
我们首先创建一个类,以下所有内容讲解都基于这个类
public class Student {
private String name;
private int age;
// 构造方法引用
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 构造方法引用
public Student(String name){
this.name = name;
this.age = 20;
}
// 构造方法引用
public Student() {
this("热巴", 18);
}
// 利用这个实例化方法引用
public String getName() {
return name;
}
// 利用这个静态方法引用
public static boolean func1(String s){
return s.length() > 2;
}
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
- 实例方法引用
格式,对象名::函数名
Student stu = new Student("杨幂", 19);
// 实例化方法引用
func(stu::getName); // 这里利用实例化对象调用show方法,可以不用自己再写lambda表达式
public static void func(Supplier<String> sp){
String str = sp.get();
System.out.println(str);
}
- 静态方法引用
格式,类名::函数名
注意:该方法应用只能通过类名调用,实例化对象不可调用
// 静态方法引用
func1(Student::func1, "杨幂"); // 调用Student类中func1静态方法
public static void func1(Predicate<String> sp, String str){
boolean b = sp.test(str);
System.out.println(b);
}
- 引用对象的构造方法
不管是无参构造还是有参构造,格式写法相同,程序会自动判断选择哪个构造函数。写法为类名::new,如Student::new
// 引用构造方法--有参数
func2(Student::new, "刘亦菲"); // 这个会自动选择有一个参数的构造方法
// 引用构造方法--无参数
func3(Student::new); // // 这个会自动选择无参数的构造方法
public static void func2(Function<String, Student> f, String str){
Student student = f.apply(str);
System.out.println(student);
}
public static void func3(Supplier<Student> sp){
Student student = sp.get();
System.out.println(student);
}
- 数组构造器引用
格式:类型名[]::new
// 数组构造器引用
func4(int[]::new, 4);
public static void func4(Function<Integer, int[]> f, Integer integer){
int[] arr = f.apply(integer);
for (int i = 0; i < arr.length; i++) {
arr[i] = i * 2 + 1;
}
System.out.println(Arrays.toString(arr));
}
获取Collection、Map、数组流
- Collection流的获取
通过Collection接口的默认方法stream(),具体调用格式为Collection对象.stream()即可获取。如:
ArrayList<String> list = new ArrayList<>();
list.stream(); // 返回结果即为流对象
- Map获取流
有三种获取流的方式
// 方式一:获取键的流
Map<String, Integer> map = new HashedMap<>();
map.keySet().stream();
// 方式二:获取值的流
map.values().stream();
// 方式三:获取键值对的流
map.entrySet.stream();
- 获取数组的流
这里又分为两种,一种是获取引用类型的流,另一种是获取基本类型的流。
// 第一种:获取基本类型的流
IntStream.of(arr); // arr为对应类型的数组,如此处为int类型的数组
LongStream.of(arr);
DoubleStream.of(arr);
// 第二种:获取引用类型的流
Stream.of(arr) // arr为引用类型的数组
4.零散的数据获取流
Stream<Integer> s = Stream.of(1, 23, 4, 5, 7, 8, 9, 0, 8);
Stream流的常用操作方法
- 逐一处理forEach
void forEach(Consumer<? super T> action); // 方法原型
示例代码:
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
// 1. forEach逐一处理
list.stream().forEach(s -> System.out.println(s + "是好样的")); // 在每一个元素后面加“好样的”
程序结果为:
张无忌是好样的
周芷若是好样的
赵敏是好样的
张强是好样的
张三丰是好样的
- 过滤filter
Stream<T> filter(Predicate<? super T> predicate); // 方法原型
示例代码:
// 先 筛选姓“张”的,再在尾部加上“是好样的”
list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s + "是好样的"));
结果为:
张无忌是好样的
张强是好样的
张三丰是好样的
- 计数count
long count(); // 方法原型
示例代码:
// 获取姓张的一共有几个
long num = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println("张姓的一共有" + num + "个");
结果为:
张姓的一共有3个
- 取出前几个limit
Stream<T> limit(long maxSize); // 方法原型
示例代码:
// 获取张姓的前一个并打印
list.stream().filter(s -> s.startsWith("张")).limit(1).forEach(System.out::println);
结果为:
张无忌
- 跳过前几个skip
Stream<T> skip(long n); // 方法原型
示例代码:
获取张姓的除了一个并打印
list.stream().filter(s -> s.startsWith("张")).skip(1).forEach(System.out::println);
- 映射(转换)map
<R> Stream<R> map(Function<? super T, ? extends R> mapper); // 函数原型
示例代码:
ArrayList<String> list1 = new ArrayList<>();
list1.add("123");
list1.add("456");
list1.add("789");
list1.add("101");
// 将String先转为Int类型,再打印加5的值。以下两种写法均可,任选其一即可
list1.stream().map(s -> Integer.valueOf(s)).forEach(s -> System.out.println(s + 5));
list1.stream().map(Integer::parseInt).forEach(s -> System.out.println(s + 5));
- 合并concat
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) // 函数原型,是一个静态方法
示例代码:
// 将list和list1的流合并
Stream.concat(list.stream(), list1.stream()).forEach(System.out::println);
- 将Stream流结果转换为各种集合之collect方法
Stream<String> stream = list.stream();
// 转为List类型
stream.collect(Collectors.toList());
// 转为Set类型
stream.collect(Collectors.toSet());
// 转为数组
stream.toArray(类型名[]::new);
注:
- 拼接方法,返回一个新流;
- 终结方法,返回的是最终的值。
前面讲的count和forEach方法为终结方法,其余的均是拼接方法(也除了collection方法)。