主要内容
- 常用函数式接口
- Stream流
学习目标
- 能够使用Function<T, R>函数式接口
- 能够使用Predicate函数式接口
- 能够理解流与集合相比的优点
- 能够理解流的延迟执行特点
- 能够通过集合或数组获取流
- 能够掌握常用的流操作
- 能够使用流进行并发操作
- 能够将流中的内容收集(转换为)到集合中
- 能够将流中的内容收集(转换为)到数组中
1、常用函数式接口
1.1 Predicate接口:测试参数真假,用来条件判断,还有与或非连接
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate<T>
接口。
1.1.1 抽象方法:test,测试条件,返回真假
Predicate
接口中包含一个抽象方法:boolean test(T t)
。用于一个条件判断的场景:
import java.util.function.Predicate;
public class Demo15PredicateTest {
private static void method(Predicate<String> predicate) {
boolean veryLong = predicate.test("HelloWorld");
System.out.println("字符串很长吗:" + veryLong);
}
public static void main(String[] args) {
method(s -> s.length() > 5);
}
}
条件判断的标准是传入的Lambda表达式逻辑,只要字符串长度大于5则认为很长。
1.1.2 默认方法:and,并且,判断两个条件是否同时成立&&(了解)
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个Predicate
条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法and
。其JDK源码为:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);//对于参数来说要求两个条件同时满足
}
如果要判断一个字符串既要包含大写“H”,又要包含大写“W”,那么:
import java.util.function.Predicate;
public class Demo16PredicateAnd {
private static void method(Predicate<String> one, Predicate<String> two) {
boolean isValid = one.and(two).test("Helloworld");
System.out.println("字符串符合要求吗:" + isValid);
}
public static void main(String[] args) {
method(s -> s.contains("H"), s -> s.contains("W"));
}
}
1.1.3默认方法:or,或者,判断两个条件是否有一个或者两个成立||
与and
的“与”类似,默认方法or
实现逻辑关系中的“或”。JDK源码为:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
如果希望实现逻辑“字符串包含大写H或者包含大写W”,那么代码只需要将“and”修改为“or”名称即可,其他都不变:
import java.util.function.Predicate;
public class Demo16PredicateAnd {
private static void method(Predicate<String> one, Predicate<String> two) {
boolean isValid = one.or(two).test("Helloworld");
System.out.println("字符串符合要求吗:" + isValid);
}
public static void main(String[] args) {
method(s -> s.contains("H"), s -> s.contains("W"));
}
}
1.1.4 默认方法:negate,取反,得到判断条件相反的结果!
“与”、“或”已经了解了,剩下的“非”(取反)也会简单。默认方法negate
的JDK源代码为:
default Predicate<T> negate() {
return (t) -> !this.test(t);
}
从实现中很容易看出,它是执行了test方法之后,对结果boolean值进行“!”取反而已。一定要在test
方法调用之前调用negate
方法,正如and
和or
方法一样:
import java.util.function.Predicate;
public class Demo17PredicateNegate {
private static void method(Predicate<String> predicate) {
boolean veryLong = predicate.negate().test("HelloWorld");
System.out.println("字符串很长吗:" + veryLong);
}
public static void main(String[] args) {
method(s -> s.length() < 5);
}
}
1.1.5 练习:集合信息筛选
- 题目
数组当中有多条“姓名+性别”的信息如下,请通过Predicate
接口的拼装将符合要求的字符串筛选到集合ArrayList
中,需要同时满足两个条件:
- 必须为女生;
- 姓名为4个字。
public class DemoPredicate {
public static void main(String[] args) {
//使用元素来判断两个条件是否同时成立
String[] array = {
"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
}
}
- 解答
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class DemoPredicate {
public static void main(String[] args) {
String[] array = {
"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
//请通过Predicate接口的拼装将符合要求的字符串元素筛选到集合ArrayList中,需要同时满足两个条件:
//1. 必须为女生;
//2. 姓名为4个字。
m((s)->{
return s.split(",")[1].contains("女"); }, (s)->{
return s.split(",")[0].length()==4;}, array);
}
public static void m(Predicate<String> p,Predicate<String> p2,String[] arr){
ArrayList<String> al = new ArrayList();
for (String s : arr) {
if (p.and(p2).test(s)){
al.add(s);
}
}
System.out.println(al);
}
}
1.2 Function接口:函数应用参数得到返回值,也有并且然后连接
java.util.function.Function<T,R>
转换接口,用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。
1.2.1 抽象方法:apply,应用,根据参数得到方法结果,即把什么东西变成什么东西
Function
接口中最主要的抽象方法为:R apply(T t)
,根据类型T的参数获取类型R的结果。使用的场景例如:将String
类型转换为Integer
类型。//把T变成字符串类型,把R变成整数类型,就知道这个方法把字符串变成整数
package day13;
import java.util.function.Function;
public class Test03 {
public static void main(String[] args) {
//Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
//使用的场景例如:将String类型转换为Integer类型。
m((s)->{
return Integer.parseInt(s);});//lambda表达式写法
m(Integer::parseInt);//通过方法引用的写法
}
public static void m(Function<String,Integer> f)