- 函数式接口
- 常用函数式接口
- Stream流
- 函数式接口的概念
- 函数式接口的定义
@FunctionalInterface
public interface 接口名 {
抽象方法
}
- 作为方法的参数
- 作为方法的返回值
public class TestInterface {
public static void main(String[] args) {
// 使用匿名内部类
method(new MyInterface() {
@Override
public void method1() {
System.out.println("method方法执行了");
}
});
// 采用Lambda表达式进行改进
method(() -> System.out.println("使用Lambda表达式method方法执行了"));
}
public static void method(MyInterface mf){
mf.method1();
}
}
public static MyInterface fun1() {
return () -> System.out.println("函数式接口作为方法的返回值...");
/*return new MyInterface() {
@Override
public void method1() {
System.out.println("函数式接口作为方法的返回值...");
}
};*/
}
总结:
什么是生产型?
Supplier介绍:
案例代码:
public static void main(String[] args) {
int i = getInt(() -> Integer.parseInt("100"));
System.out.println(i);
}
public static int getInt(Supplier<Integer> s) {
// 通过T get方法来生成数据
return s.get();
}
public class SupplierTest {
public static void main(String[] args) {
// 求数组中的最大值
int[] arr = {1,2,3,4,5};
int max_value = getMax(() ->{
// 定义一个变量,假设这个变量是最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
});
System.out.println(max_value);
}
public static int getMax(Supplier<Integer> s) {
// 通过T get方法来生成数据
return s.get();
}
}
总结:
01 什么是消费型?
02 Consumer介绍:
03 Consumer 接口的默认方法andThen
案例代码:
public class ConsumerDemo1 {
public static void main(String[] args) {
method1("小希",str -> System.out.println(str));
// 定义一个字符串
String name = "姓名:麻生希";
method2(name,
str -> System.out.println(str.split(":")[0]),
str -> System.out.println(str.split(":")[1])
);
}
public static void method2(String name, Consumer<String> con1,Consumer<String> con2){
// 使用andThen
con1.andThen(con2).accept(name);
}
// 使用Consumer接口消费一个字符串
public static void method1(String name, Consumer<String> con){
con.accept(name);
}
}
04 Consumer接口练习_字符串拼接输出
将打印姓名的动作作为第一个 Consumer 接口的Lambda实例,
将打印性别的动作作为第二个 Consumer 接口的Lambda实例,
将两个 Consumer 接口按照顺序“拼接”到一起。
public class ConsumerTest {
public static void main(String[] args) {
// 定义一个数组
String[] arr = {"柳岩,38","汪峰,40","杨幂,30"};
// 遍历数组
for (String str : arr) {
// 将遍历到的字符串 传递到方法中进行消费数据
fun(str, name -> System.out.print("姓名:"+name.split(",")[0]),
name -> System.out.println(",年龄:"+name.split(",")[1])
);
}
}
public static void fun(String name, Consumer<String> con1, Consumer<String> con2){
// 使用andThen
con1.andThen(con2).accept(name);
}
}
01 Predicate概述:
02 Predicate接口中的方法
03 Predicate 的基本使用
案例演示
public class PredicateDemo {
public static void main(String[] args) {
// 1.定义一个字符串
String str = "lasjdflasjfl";
// 2.判断字符串是否包含"w"
boolean flag = isStr(str, s -> {
return s.contains("w");
});
// 输出结果
System.out.println(flag);
}
// 使用Predicate接口判断一个字符串是否是包含XXX
public static boolean isStr(String str , Predicate<String> pre){
// return pre.test(str);
return pre.negate().test(str);
}
}
04 Predicate 接口中的默认方法
and:
相当于 &&
有false则为false
or:
相当于 ||
有 true 则为 true
negate:
相当于 !
非true则为false
非false则为true
05 Predicate接口练习_集合信息筛选
需求:
String[] strArray = {“林青霞,30”, “柳岩,34”, “张曼玉,35”, “貂蝉,31”, “王祖贤,33”};
字符串数组中有多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合
需要同时满足两个条件:
分析:
public class PredicateTest {
public static void main(String[] args) {
String[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"};
ArrayList<String> array = myFilter(
// 需要遍历的数组
strArray,
// 姓名长度大于2
s -> s.split(",")[0].length() > 2,
// 年龄大于33
// 首先,截取年龄,截取的结果是一个字符串,
// 想要跟整数进行比较,必须将字符串的年龄转换成整数
s -> Integer.parseInt(s.split(",")[1]) > 33
);
for (String str : array) {
System.out.println(str);
}
}
//通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中
private static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2) {
//定义一个集合
ArrayList<String> array = new ArrayList<String>();
//遍历数组
for (String str : strArray) {
if (pre1.and(pre2).test(str)) {
array.add(str);
}
}
return array;
}
}
接口用来根据一个类型的数据得到另一个类型的数据,“123” --> 123 —> “123”
前者称为前置条件,后者称为后置条件。
映射: 转换数据的 String --> Integer
Function接口中最主要的抽象方法为:
R apply(T t),根据类型T的参数获取类型R的结果。
应用场景: 将字符串转换为int 将int转换为String…
02 Function 接口中的默认方法
案例代码:
public class FunctionDemo1 {
public static void main(String[] args) {
method("123",
s -> Integer.parseInt(s),
i -> (i + 100)+""
);
}
// 将字符串的数据转换成int 然后在将int数据转换成字符串
public static void method(String str, Function<String,Integer> fun1,Function<Integer, String> fun2) {
String s = fun1.andThen(fun2).apply(str);
System.out.println(s);
}
}
案例演示:
String s = “林青霞,30”;
将字符串截取得到数字年龄部分 String String
将上一步的年龄字符串转换成为int类型的数据 String Integer
将上一步的int数据加70,得到一个int结果,在控制台输出 Integer Integer
第一次是把String类型转换为了String类型 所以我们可以使用Function
fun1 String i = fun1.apply(“30”);
第二次是把Integer类型转换为String类型,所以我们可以使用Functionfun2int s = fun2.apply(i);
第三次是把Integer类型转换为Integer类型, 所以我们可以使用Functionfun3 int age = fun2.apply(s)+70;
我们可以使用andThen方法,把三次转换组合在一起使用
String s = fun1.andThen(fun2).andThen(fun3).apply(“30”);
fun1先调用apply方法,把字符串转换为String
fun2再调用apply方法,把String转换为Integer
fun3再调用apply方法,把Integer转换为Integer
案例代码:
public class FunctionTest {
public static void main(String[] args) {
String s = "林青霞,30";
// convert(s, (String ss) -> {
// return ss.split(",")[1];
// },(String ss) -> {
// return Integer.parseInt(ss);
// },(Integer i) -> {
// return i + 70;
// });
convert(
// 要操作的字符串
s,
// 截取字符串年龄
ss -> ss.split(",")[1],
// 将字符串的年龄转换成int类型的年龄
ss -> Integer.parseInt(ss),
// 将转换后的int的年龄 + 70
i -> i + 70
);
// convert(s, ss -> ss.split(",")[1], Integer::parseInt, i -> i + 70);
}
private static void convert(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
// Integer i = fun1.andThen(fun2).andThen(fun3).apply(s);
int i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.println(i);
}
}
- 在Java 8中,得益于Lambda所带来的函数式编程
* 引入了一个全新的Stream概念,用于解决已有集合类库现有的弊端
- 流式思想的函数模型拼接
大白话: 对一组数据进行多次过滤…筛选…统计…
数据源: A B C D E
筛选后: A B C D
映射后: Aa Bb Cc Dd
跳过后: Bb Cc Dd
- 所有的集合都可以通过 stream 默认方法获取流
1. List:
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
2. Set:<br>
Set<String> set = new Set<String>();
Stream<String> listStream = set.stream();
3. Map:<br>
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
Stream<T> stream = Stream.of(T...args);
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 filter(Predicate predicate): 对流中的数据进行过滤
重点 : Stream流只能消费一次
filter案例演示
/*
Stream filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
*/
public class StreamDemo01 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//需求1:把list集合中以张开头的元素在控制台输出
// list.stream().filter((String s) -> {
// return s.startsWith("张");
// }).forEach(System.out::println);
Stream<String> stream = list.stream().filter(s -> s.startsWith("张"));
stream.forEach(System.out::println);
// 流用完就用完了,是一次性的,如果再想用重新获取流即可
// 流达到最终一个操作之后,如果再使用这个流:stream has already been operated upon or closed
// stream.filter(s -> s.startsWith("张"));
System.out.println("--------");
//需求2:把list集合中长度为3的元素在控制台输出
list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
System.out.println("--------");
//需求3:把list集合中以张开头的,长度为3的元素在控制台输出
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
}
}
参数是一个long型,如果传入的参数, 大于集合的长度, 那么返回的结果, 将会是集合中所有的数据.
如果传入的是一个负数的参数, 那么会出现异常.
limit(n); // 1-n
如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流
示例代码:
/*
Stream limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据
Stream skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流
*/
public class StreamDemo02 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
list.stream().filter(name-> name.length() == 3).limit(2).forEach(System.out::println);
list.stream().filter(name-> name.length() == 3).skip(2).forEach(System.out::println);
//需求1:取前3个数据在控制台输出
list.stream().limit(3).forEach(System.out::println);
System.out.println("--------");
//需求2:跳过3个元素,把剩下的元素在控制台输出
list.stream().skip(3).forEach(System.out::println);
System.out.println("--------");
//需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
list.stream().skip(2).limit(2).forEach(System.out::println);
}
}
concat : 将两个流, 整合为一个流
count方法 : 去除流中的重复的元素,根据Object.equals(Object)
示例代码:
/*
static Stream concat(Stream a, Stream b):合并a和b两个流为一个流
Stream distinct():返回由该流的不同元素(根据Object.equals(Object) )组成的流
*/
public class StreamDemo03 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//需求1:取前4个数据组成一个流
Stream<String> s1 = list.stream().limit(4);
//需求2:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
//需求3:合并需求1和需求2得到的流,并把结果在控制台输出
// Stream.concat(s1,s2).forEach(System.out::println);
//需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
Stream.concat(s1,s2).distinct().forEach(System.out::println);
}
}
sorted 方法 : 根据自然顺序排序
sorted(Comparator comparator)方法: 根据提供的Comparator进行排序
示例代码:
/*
Stream sorted():返回由此流的元素组成的流,根据自然顺序排序
Stream sorted(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序
Comparator 接口中的方法 int compare(T o1, T o2)
*/
public class StreamDemo04 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("liuyan");
list.add("zhangmin");
list.add("zhangwuji");
//需求1:按照字母顺序把数据在控制台输出
// list.stream().sorted().forEach(System.out::println);
//需求2:按照字符串长度把数据在控制台输出
// list.stream().sorted((s1, s2) -> s1.length() - s2.length()).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);
}
}
/*
Stream map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流
Function接口中的方法 R apply(T t)
IntStream mapToInt(ToIntFunction mapper):返回一个IntStream其中包含将给定函数应用于此流的元素的结果
IntStream:表示原始 int 流
ToIntFunction接口中的方法 int applyAsInt(T value)
*/
public class StreamDemo05 {
public static void main(String[] args) {
//创建一个集合,存储多个字符串元素
ArrayList<String> list = new ArrayList<String>();
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);
// list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
//int sum() 返回此流中元素的总和
int result = list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(result);
}
}
当前forEach是一个方法, 并不是增强for循环
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作:
案例代码
public class StreamTest {
public static void main(String[] args) {
ArrayList<String> maleList = new ArrayList<>();
maleList.add("周润发");
maleList.add("成龙");
maleList.add("刘德华");
maleList.add("吴京");
maleList.add("周星驰");
maleList.add("李连杰");
ArrayList<String> femaleList = new ArrayList<>();
femaleList.add("林心如");
femaleList.add("张曼玉");
femaleList.add("林青霞");
femaleList.add("柳岩");
femaleList.add("林志玲");
femaleList.add("王祖贤");
// Stream maleStream = maleList.stream().filter(s -> s.length() == 3).limit(3);
// Stream femaleStream = femaleList.stream().filter(s -> s.startsWith("林")).skip(1);
// Stream.concat(maleStream,femaleStream).map(Actor::new).forEach(p -> System.out.println(p.getName()));
Stream.concat(
maleList.stream().filter(s -> s.length() == 3).limit(3),
femaleList.stream().filter(s -> s.startsWith("林")).skip(1)).
map(Actor::new).
forEach(p -> System.out.println(p.getName())
);
}
}