课程笔记Day16
- Lambda 表达式
- 方法引用
- Stream流
第一章 Lambda表达式
第01节 基础理论
lambda表达式的体验
发现问题
以前写 匿名内部类的时候,会觉得代码非常的繁琐。写起来比较麻烦。
体验 Lambda表达式
接口
//接口
public interface JieKou {
//抽象方法
public abstract void methodAbstract();
}
接口实现类
//实现类
public class ShiXian implements JieKou {
@Override
public void methodAbstract() {
System.out.println("接口实现类...");
}
}
测试类
public class Test {
public static void main(String[] args) {
//可以使用多态的写法
JieKou kou = new ShiXian();
function(kou);
//可以使用匿名内部类的写法
function(new JieKou() {
@Override
public void methodAbstract() {
System.out.println("匿名内部类");
}
});
//采用Lambda表达式对于匿名内部类进行简化。
function(()->System.out.println("Lambda"));
}
//将方法的参数定义为接口
public static void function(JieKou kou){
kou.methodAbstract();
}
}
lambda表达式的格式
格式:
(参数列表)->{ 方法体; }
1. 小括号:参数列表。指的是 接口当中抽象方法的参数列表。
2. 箭头: 就是一个指向,没有具体的含义。可以理解为:将参数传递给方法体。
3. 大括号: 方法体。指的是 接口当中抽象方法的具体实现。
前提:
如果想要使用 Lambda 表达式,则必须有 函数式接口。
什么是函数式接口呢?
函数式接口: 有且仅有一个抽象方法的接口,就叫做函数式接口。
如何去校验是否是正确的函数式接口呢?
可以采用注解 @FunctionalInterface
辨别函数式接口
第02节 系统函数式接口
Supplier
源代码
//作用:只出不进
@FunctionalInterface
public interface Supplier<T> {
T get();
}
测试类
import java.util.function.Supplier;
//目标:学习系统提供的Supplier接口
public class Test01 {
public static void main(String[] args) {
//匿名内部类版本
function(new Supplier<String>() {
@Override
public String get() {
return "sleep 真香";
}
});
//采用 Lambda 表达式简化
function(()->{return "sleep 真香,尤其是上课sleep";});
}
//定义一个方法,该方法的参数是函数式接口
public static void function(Supplier<String> fun){
String s = fun.get();
System.out.println(s);
}
}
Consumer
源代码
//作用:只进不出
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
测试类
import java.util.function.Consumer;
//函数式接口 Consumer的使用
public class Test02 {
public static void main(String[] args) {
//调用方法, 采用的是匿名内部类的写法
function(100, new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
//如果想要写 lambda表达式应该怎么写呢?
function(100,(Integer integer)->{ System.out.println(integer);});
}
//函数式接口作为方法的参数传递
public static void function(Integer ii,Consumer<Integer> fun){
fun.accept(ii);
}
}
Predicatie
源代码
//作用:条件判断
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
测试类
import java.util.function.Predicate;
//目标:学习Predicate 函数式接口的使用
public class Test03 {
public static void main(String[] args) {
//匿名内部类
function("张无忌", new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("王");
}
});
//Lambda表达式的写法
function("隔壁老王",(String s)->{return s.startsWith("王");});
}
public static void function(String str,Predicate<String> fun){
boolean flag = fun.test(str);
System.out.println("flag = " + flag);
}
}
Function
源代码
//作用:类型转换
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
测试类
import java.util.function.Function;
//目标:学习 Function 函数式接口的使用
public class Test04 {
public static void main(String[] args) {
//匿名内部类写法
function("hello", new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
//Lambda表达式的写法
function("world",(String s)->{return s.length();});
}
//写一个方法,方法的参数是函数式接口
public static void function(String str,Function<String,Integer> fun){
Integer num = fun.apply(str);
System.out.println(num);
}
}
第03节 省略策略
关于 Lambda表达式,除了标准格式外,还可以继续的简化代码。
1. 什么时候,小括号可以省略呢?
只有一个参数的时候,可以省略小括号不写。
2. 什么时候,大括号可以省略呢?
在方法体当中,只有一句话的时候,可以省略大括号,分号,return语句。
3. 百分百可以省略的是什么?
我们 参数列表的数据类型,可以百分百省略。
第04节 Lambda和匿名内部类
说明
1. 区别一:引用简化方式不同。
A. 匿名内部类,他可以作用于 接口或者是类
B. Lambda表达式, 他只能作用于函数式接口
2. 区别二: 底层实现不同。
A. 匿名内部类,底层产生class文件
B. Lambda表达式,底层没有 class 文件
第二章 方法引用
第01节 体验一下
import java.util.function.Consumer;
//目标:体验方法引用的好处
public class Test01 {
public static void main(String[] args) {
//采用Lambda表达式的写法
method("hello",str-> System.out.println(str));
//直接使用方法引用
method("world",System.out::println);
}
public static void method(String str,Consumer<String> con){
con.accept(str);
}
}
小结:
我们发现,采用方法引用,比lambda表达式更加的简单。
条件会更加的苛刻。
你要做某件事情,刚好发现别人也要做这件事情,就顺带的使用他的事情,一起做了。
第02节 成员方法引用
普通类
//学生类
public class Student {
//定义方法,喊出你的名字
public void callName(String name){
System.out.println("我叫"+name);
}
}
测试类
import java.util.function.Consumer;
public class Test02 {
public static void main(String[] args) {
//原始的做法:
method("黄雨浩",name-> System.out.println("我叫"+name));
//直接引用方法
method("江少东",new Student()::callName);
}
//定义一个方法,进行自我介绍。
public static void method(String name,Consumer<String> con){
con.accept(name);
}
}
//我叫黄雨浩
//我叫江少东
小结:成员方法引用格式:
对象名称::方法名称
第03节 静态方法引用
普通类
public class Teacher {
//定义方法,喊出你的名字
public static void callName(String name){
System.out.println("点名"+name);
}
}
测试类
import java.util.function.Consumer;
public class Test03 {
public static void main(String[] args) {
//原始的做法:
method("黄雨浩",name-> System.out.println("点名"+name));
//直接引用左侧的方法
method("江少东",Teacher::callName);
}
//定义一个方法,进行自我介绍。
public static void method(String name,Consumer<String> con){
con.accept(name);
}
}
//点名黄雨浩
//点名江少东
小结:静态方法的引用:
类名称::方法名称
第04节 构造方法引用
普通类
public class Student{
}
测试类
import java.util.function.Supplier;
//目标:学习构造方法引用
public class Test04 {
public static void main(String[] args) {
//将对象,进行打印输出
Student stu1 = makeObject(() -> new Student());
System.out.println("stu1 = " + stu1);
//采用方法引用
Student stu2 = makeObject(Student::new);
System.out.println("stu2 = " + stu2);
}
//泛型方法。返回一个你需要的对象
public static <T> T makeObject(Supplier<T> sup){
T t = sup.get();
return t;
}
}
小结:构造方法引用格式:
类名称::new
第三章 Stream流
第01节 基础理论
我们以前针对于集合或者数组的操作是非常频繁的。
例如:
第一步做集合 筛选的操作(根据条件1筛选)
第二步做集合 筛选的操作(根据条件2筛选)
第三步做集合 合并的操作(将两个集合数据进行合并)
第四步做集合 去重的操作(将重复的数据进行过滤)
第五步做集合 排序的操作(将集合数据按照升序排列)
快速入门
public static void main(String[] args) {
ArrayList<String> one = new ArrayList<>();
Collections.addAll(one,"河北省","山西省","吉林省","辽宁省","黑龙江省","陕西省","甘肃省","青海省","山东省","福建省","浙江省","台湾省","河南省","湖北省","湖南省","江西省","江苏省","安徽省","广东省","海南省","四川省","贵州省","云南省");
ArrayList<String> two = new ArrayList<>();
Collections.addAll(two,"北京市","天津市","上海市","重庆市");
ArrayList<String> three = new ArrayList<>();
Collections.addAll(three,"内蒙古自治区","新疆维吾尔自治区","宁夏回族自治区","广西壮族自治区","西藏自治区");
ArrayList<String> four = new ArrayList<>();
Collections.addAll(four,"香港特别行政区","澳门特别行政区");
Stream<String> sm1 = Stream.concat(one.stream(), two.stream());
Stream<String> sm2 = Stream.concat(three.stream(), four.stream());
long count = Stream.concat(sm1, sm2).filter(s -> s.length() == 3).count();
System.out.println("xxcount = " + count);
}
流Stream的流程图
第02节 常用API
获取流的操作
类别 | 做法 | 例子 |
---|---|---|
单列集合 | 集合对象名称.stream( ); | mList.stream( ); mSet.stream( ); |
双列集合 | 将双列集合转换成为单列集合,再调用 stream( ) 方法 | mMap.keySet( ).stream( ) mMap.values( ).stream( ) |
同类数据 | 有多个数据类型相同的数据,直接使用静态方法 of | Stream.of(数据1,数据2,数据3); |
常用方法
方法名 | 方法作用 | 返回值类型 | 方法种类 |
---|---|---|---|
count | 统计个数 | long | 终结 |
foreach | 遍历 | void | 终结 |
filter | 过滤 | Stream | 中间 |
limit | 限定前几个 | Stream | 中间 |
skip | 跳过前几个 | Stream | 中间 |
map | 映射 | Stream | 中间 |
sorted | 排序 | Stream | 中间 |
distinct | 去重 | Stream | 中间 |
collect | 收集 | List、Set、Map | 收集 |
说明:
- 终结:操作完毕之后,不再是 Stream 流对象。
- 中间:操作完毕之后,还是 Stream流对象,还可以继续调用 Stream流当中的方法。
- 收集:操作完毕之后,可以将 Stream流转换成为集合对象。
第03节 Stream流练习
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
我国有34个省级行政区,分别是:
23个省:河北省、山西省、吉林省、辽宁省、黑龙江省、陕西省、甘肃省、青海省、山东省、福建省、浙江省、台湾省、河南省、湖北省、湖南省、江西省、江苏省、安徽省、广东省、海南省、四川省、贵州省、云南省。
4个直辖市:北京市、天津市、上海市、重庆市。
5个自治区:内蒙古自治区、新疆维吾尔自治区、宁夏回族自治区、广西壮族自治区、西藏自治区。
2个特别行政区:香港特别行政区、澳门特别行政区。
请使用流依次完成下列操作:
题目01:统计三个字的省份的个数
题目02:统计名字中包含方位名词的省份(东西南北)的个数
题目03:打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
题目04:将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中
*/
@SuppressWarnings("all")
public class Test06 {
public static void main(String[] args) {
ArrayList<String> one = new ArrayList<>();
Collections.addAll(one, "河北省", "山西省", "吉林省", "辽宁省", "黑龙江省", "陕西省", "甘肃省", "青海省", "山东省", "福建省", "浙江省", "台湾省", "河南省", "湖北省", "湖南省", "江西省", "江苏省", "安徽省", "广东省", "海南省", "四川省", "贵州省", "云南省");
ArrayList<String> two = new ArrayList<>();
Collections.addAll(two, "北京市", "天津市", "上海市", "重庆市");
ArrayList<String> three = new ArrayList<>();
Collections.addAll(three, "内蒙古自治区", "新疆维吾尔自治区", "宁夏回族自治区", "广西壮族自治区", "西藏自治区");
ArrayList<String> four = new ArrayList<>();
Collections.addAll(four, "香港特别行政区", "澳门特别行政区");
//将四个集合全部存放到Stream流当中
Stream<String> sm1 = Stream.concat(one.stream(), two.stream());
Stream<String> sm2 = Stream.concat(three.stream(), four.stream());
Stream<String> sm = Stream.concat(sm1, sm2);
//先将流对象,收集到集合当中
List<String> collect = sm.collect(Collectors.toList());
//题目01:统计三个字的省份的个数
long count1 = collect.stream().filter(s -> s.length() == 3).count();
System.out.println("count1 = " + count1);
//题目02:统计名字中包含方位名词的省份(东西南北)的个数
long count2 = collect.stream().filter(s -> s.contains("东") || s.contains("南") || s.contains("西") || s.contains("北")).count();
System.out.println("count2 = " + count2);
//题目03:打印名字中包含方位名词的普通省份(非自治区直辖市特别行政区)的名字
collect.stream().filter(s -> s.contains("东") || s.contains("南") || s.contains("西") || s.contains("北")).filter(s -> s.contains("区") == false && !s.contains("市")).forEach(System.out::println);
//题目04:将所有的特殊省份(自治区直辖市特别行政区)提取出来并放到新数组中
List<String> mList = collect.stream().filter(s -> s.contains("市") || s.contains("区")).collect(Collectors.toList());
String[] array = mList.toArray(new String[mList.size()]);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i] + ",索引:" + i);
}
}
}
//山东、山西、河南、河北、湖南、湖北、广东、广西、陕西、北京、江西、海南、西藏、云南
//山东、山西、河南、河北、湖南、湖北、广东、陕西、江西、云南、海南
今天总结
今天任务不要出门,多学多练,变异毒株德尔塔病毒来了,大家要保护好自己,不要出门,讲卫生,勤洗手,勤通风。