Stream和方法引用
1. Stream流
1.1. Stream流引入
Stream流完全不是I/O流,按照流水线处理方式来考虑代码中的思想。
JDK1.8 之后,我们拥有了Lambda表达式,让代码的中心偏向解决实际问题,直到重点,可以提高效率。
Stream流中使用了大量Lambda表达式,利用Lambda操作方式,提供开发效率
1.2 传统遍历方式和Stream类处理方式对比
package com.qfedu.a_stream;
import java.util.ArrayList;
public class Demo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("宫保鸡丁");
list.add("酱牛肉");
list.add("羊肉串");
list.add("烤羊排");
list.add("羊肉汤");
list.add("驴肉火烧");
ArrayList<String> list1 = new ArrayList<>();
for (String s : list) {
if (s.contains("肉")) {
list1.add(s);
}
}
ArrayList<String> list2 = new ArrayList<>();
for (String s : list1) {
if (3 == s.length()) {
list2.add(s);
}
}
for (String s : list2) {
System.out.println(s);
}
}
}
package com.qfedu.a_stream;
import java.util.ArrayList;
public class Demo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("宫保鸡丁");
list.add("酱牛肉");
list.add("羊肉串");
list.add("烤羊排");
list.add("羊肉汤");
list.add("驴肉火烧");
list.stream()
.filter(s->s.contains("肉"))
.filter(s -> 3 == s.length())
.forEach(s -> System.out.println(s));
}
}
1.3 Stream流对应的思想
请你忘掉原先的IO流思想
流水线:
原材料从头到尾只会占用一份空间,中间的过程中不会占用空间。最后生成一个结果。
Stream流有一些特征:
1. 带有很多Stream流操作的方法, filter,limit,map,sorted,skip...这些方法大多是都会使用到函数式接口,有lambda表达式
2. 整个Stream流模型操作过程中,只有执行到count,foreach这些方法,操作真正的执行中的模型,如果不存在结果导向,中间的所有操作是无效的,这里得益于Lambda表达式的延后性
3. Stream流是存在一定的管道性 Pipelining 流水线
1.4 获取Stream流
java.util.stream.Stream<T> JDK1.8的新特征
1. 所有的Collection<T>集合都有对应的Stream();
2. 可以通过Stream类中的static Stream of()获取
static Stream<T> of(T... t);
static Stream<T> of(T t);
package com.qfedu.b_streamget;
import java.util.*;
import java.util.stream.Stream;
public class Demo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
HashSet<String> set1 = new HashSet<>();
Stream<String> stream1 = set1.stream();
HashMap<String, String> map = new HashMap<>();
Set<String> keySet = map.keySet();
Stream<String> stream2 = keySet.stream();
Collection<String> values = map.values();
Stream<String> stream3 = values.stream();
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Stream<Map.Entry<String, String>> stream4 = entrySet.stream();
Stream<String> stringStream = Stream.of("酱牛肉", "羊肉抓饭", "羊肉汤", "羊蝎子");
String[] arr = {"黄河大鲤鱼", "方中山胡辣汤", "萧记烩面", "蔡记蒸饺", "葛记焖饼"};
Stream<String> arrStream = Stream.of(arr);
ArrayList<String> list1 = new ArrayList<>();
Stream<ArrayList<String>> list11 = Stream.of(list1);
}
}
1.5 Stream常用方法
延迟方法:
返回值类型依然是Stream接口本身,并没有影响我们操作真正的资源
允许链式操作,
例如
filter(XXX).limit(XXX).sorted(XXX).
终结方法:
返回值类型不是Stream接口本身,要么处理数据,要么返回其他类型数据,并且不再支持Stream流对象链式操作,count,foreach
1.5.1 foreach方法【终结方法】
void foreach(Consumer<? super T> action);
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class Demo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("蛋炒饭");
list.add("虎皮青椒");
list.add("手撕包菜");
list.add("鲱鱼罐头");
Stream<String> stream = list.stream();
stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
stream.forEach(string -> System.out.println(string));
stream.forEach(System.out::println);
}
}
1.5.2 filter方法
Stream<T> filter(Predicate<? super T> condition);
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("擀面皮");
list.add("肉夹馍");
list.add("冰峰");
list.add("水盆羊肉");
Stream<String> stringStream = list.stream().filter(s -> s.length() >= 3);
stringStream.forEach(System.out::println);
Stream<String> stringStream1 = stringStream.filter(s -> 4 == s.length());
stringStream1.forEach(System.out::println);
}
}
1.5.3 map方法
<R> Stream<R> map(Function<? super T, ? super R> fun);
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1,骚磊,16");
list.add("2,骚杰,66");
list.add("3,老黑,46");
list.add("4,老付,36");
list.add("5,污云,56");
list.add("6,帅栋,26");
System.out.println(list);
Stream<Person> personStream = list.stream().map(s -> {
String[] split = s.split(",");
Person person = new Person();
person.setId(Integer.parseInt(split[0]));
person.setName(split[1]);
person.setAge(Integer.parseInt(split[2]));
return person;
});
personStream.forEach(System.out::println);
}
}
1.5.4 count方法【终结方法】
long count();
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
public class Demo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("擀面皮");
list.add("肉夹馍");
list.add("冰峰");
list.add("水盆羊肉");
long count = list.stream().filter(s -> s.length() >= 3).count();
System.out.println(count);
}
}
1.5.5 limit方法
Stream<T> limit(long maxSize);
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("红旗");
list.add("领克");
list.add("吉利");
list.add("比亚迪");
list.add("长安");
list.add("五菱宏光");
Stream<String> stream = list.stream();
stream.limit(5).forEach(System.out::println);
}
}
1.5.6 skip方法
Stream<T> skip(long n);
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
public class Demo6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("陆巡");
list.add("高R");
list.add("RS7");
list.add("s4");
list.add("霸道");
list.add("道奇");
list.stream().skip(2).forEach(System.out::println);
}
}
1.5.7 concat方法
static Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo7 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("红旗");
list.add("领克");
list.add("吉利");
list.add("比亚迪");
list.add("长安");
list.add("五菱宏光");
ArrayList<String> list1 = new ArrayList<>();
list1.add("陆巡");
list1.add("高R");
list1.add("RS7");
list1.add("s4");
list1.add("霸道");
list1.add("道奇");
Stream<String> stream = list.stream();
Stream<String> stream1 = list1.stream();
Stream<String> concat = Stream.concat(stream, stream1);
concat.forEach(System.out::println);
}
}
1.5.8 原始操作方式和Stream流方式对比
1. 一个String类型的字符串集合,"1,骚磊,16"
2. 过滤没有5的数据
3. 跳过前三个数据
4. 限制得到前5个数据
5. 两个String类型集合字符串合并
6. 转换成Person类型
7. 展示数据
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
public class Demo8 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("1,骚磊,15");
list1.add("2,骚杰,65");
list1.add("3,老黑,45");
list1.add("4,老付,56");
list1.add("5,污云,56");
list1.add("6,帅栋,26");
list1.add("7,帅栋,56");
list1.add("8,帅栋,25");
list1.add("9,帅栋,26");
list1.add("10,帅栋,26");
list1.add("11,帅栋,25");
list1.add("12,帅栋,56");
list1.add("13,帅栋,55");
ArrayList<String> list2 = new ArrayList<>();
for (String s : list1) {
if (s.contains("5")) {
list2.add(s);
}
}
System.out.println(list2);
ArrayList<String> list3 = new ArrayList<>();
for (int i = 3; i < list2.size(); i++) {
list3.add(list2.get(i));
}
System.out.println(list3);
ArrayList<String> list4 = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list4.add(list3.get(i));
}
ArrayList<String> list5 = new ArrayList<>();
list5.add("1,骚磊,15");
list5.add("2,骚杰,65");
list5.add("3,老黑,45");
list5.add("4,老付,56");
list5.add("5,污云,56");
list4.addAll(list5);
ArrayList<Person> list6 = new ArrayList<>();
for (String s : list4) {
String[] split = s.split(",");
Person person = new Person();
person.setId(Integer.parseInt(split[0]));
person.setName(split[1]);
person.setAge(Integer.parseInt(split[2]));
list6.add(person);
}
for (Person person : list6) {
System.out.println(person);
}
}
}
package com.qfedu.c_streamfunction;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo9 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("1,骚磊,15");
list1.add("2,骚杰,65");
list1.add("3,老黑,45");
list1.add("4,老付,56");
list1.add("5,污云,56");
list1.add("6,帅栋,26");
list1.add("7,帅栋,56");
list1.add("8,帅栋,25");
list1.add("9,帅栋,26");
list1.add("10,帅栋,26");
list1.add("11,帅栋,25");
list1.add("12,帅栋,56");
list1.add("13,帅栋,55");
ArrayList<String> list2 = new ArrayList<>();
list2.add("1,骚磊,15");
list2.add("2,骚杰,65");
list2.add("3,老黑,45");
list2.add("4,老付,56");
list2.add("5,污云,56");
list2.add("6,帅栋,26");
list2.add("7,帅栋,56");
Stream<String> stream = list1.stream();
Stream<String> limit = stream.filter(s -> s.contains("5")).
skip(3).
limit(5);
Stream.concat(limit, list2.stream()).map(s -> {
String[] split = s.split(",");
Person person = new Person();
person.setId(Integer.parseInt(split[0]));
person.setName(split[1]);
person.setAge(Integer.parseInt(split[2]));
return person;
}).forEach(System.out::println);
}
}
2. 方法引用
2.1 Lambda冗余问题以及方法引用初识
package com.qfedu.d_methodreference;
@FunctionalInterface
interface PrintMethod {
void print(String str);
}
public class Demo1 {
public static void main(String[] args) {
testPrint("郑州加油!!!", str -> System.out.println(str));
testPrint("中国加油!!!祖国万岁!!!", System.out::println);
}
public static void testPrint(String str, PrintMethod pm) {
pm.print(str);
}
}
2.2 方法引用小要求
testPrint("郑州加油!!!", str -> System.out.println(str));
testPrint("郑州加油!!!", System.out::println);
1. 明确对象
对象 ==> 调用者
类对象,类名,super,this,构造方法,数组构造方法
2. 明确的执行方法
该方法只有名字不需要显式出现参数
3. 需要处理的数据
【联想,推导,省略】
4. :: 方法引用格式
2.3 通过类对象来执行方法引用
1. 明确对象
类对象
2. 明确执行的方法
自定义
3. 处理的数据
简单要求为String类型
package com.qfedu.e_objectmethodreference;
@FunctionalInterface
public interface Printable {
void method(String str);
}
package com.qfedu.e_objectmethodreference;
public class ObjectMethodReference {
public void print(String str) {
System.out.println(str.toLowerCase());
}
public void printSubstring(String str) {
System.out.println(str.substring(3));
}
public void saolei() {
System.out.println("无参数方法");
}
}
```
```java
package com.qfedu.e_objectmethodreference;
public class Demo2 {
public static void main(String[] args) {
ObjectMethodReference obj = new ObjectMethodReference();
test(obj::printSubstring);
}
public static void test(Printable printable) {
printable.method("ABCDE");
}
}
```
##### 2.4 通过类名来执行方法引用
```java
package com.qfedu.f_classmethodreference;
import java.util.List;
@FunctionalInterface
public interface PrintList {
void print(List<?> list);
}
```
```java
package com.qfedu.f_classmethodreference;
import java.util.List;
public class ClassMethodReference {
public static void showListInfo(List<?> list) {
for (Object o : list) {
System.out.println(o);
}
}
}
```
```java
package com.qfedu.f_classmethodreference;
import java.util.ArrayList;
public class Demo3 {
public static void main(String[] args) {
testClass(ClassMethodReference::showListInfo);
testClass(list -> {
for (Object o : list) {
System.out.println(o);
}
});
}
public static void testClass(PrintList printList) {
ArrayList<String> list = new ArrayList<>();
list.add("BMW");
list.add("Audi");
printList.print(list);
}
}
```
##### 2.5 通过super关键字执行方法引用
```java
package com.qfedu.g_supermethodreference;
public interface SaySomeThing {
void say();
}
```
```java
package com.qfedu.g_supermethodreference;
public class Father {
public void sayHello() {
System.out.println("你好 Java");
}
}
```
```java
package com.qfedu.g_supermethodreference;
import java.util.Scanner;
public class Son extends Father {
public static void main(String[] args) {
testSay(() -> System.out.println("你好"));
new Son().sonMethod();
}
public static void testSay(SaySomeThing sst) {
sst.say();
}
public void sonMethod() {
testSay(super::sayHello);
}
}
```
##### 2.6 通过this关键字执行方法引用
```java
package com.qfedu.h_thismethodreference;
public interface ORM {
String toStringType(int i);
}
```
```java
package com.qfedu.h_thismethodreference;
public class ThisDemo {
public void test() {
String s = testThis(i -> i + ":");
System.out.println(s);
String s1 = testThis(this::turn);
}
public String turn(int i) {
return i + ":字符串";
}
public static String testThis(ORM orm) {
return orm.toStringType(10);
}
public static void main(String[] args) {
new ThisDemo().test();
}
}
```