课程笔记Day16
第一章 Lambda表达式
第01节 基础理论
第02节 系统函数式接口
第03节 省略策略
第04节 Lambda和匿名内部类
第二章 方法引用
第01节 体验一下
第02节 成员方法引用
第03节 静态方法引用
第04节 构造方法引用
第三章 Stream流
第01节 基础理论
第02节 常用API
课程笔记Day16
Lambda 表达式
方法引用
Stream流
JDK8的时间类
第一章 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表达式的格式
格式:
(参数列表)->{ 方法体; }
小括号:参数列表。指的是 接口当中抽象方法的参数列表。
箭头: 就是一个指向,没有具体的含义。可以理解为:将参数传递给方法体。
大括号: 方法体。指的是 接口当中抽象方法的具体实现。
前提:
如果想要使用 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表达式,除了标准格式外,还可以继续的简化代码。
什么时候,小括号可以省略呢?
只有一个参数的时候,可以省略小括号不写。
什么时候,大括号可以省略呢?
在方法体当中,只有一句话的时候,可以省略大括号,分号,return语句。
百分百可以省略的是什么?
我们 参数列表的数据类型,可以百分百省略。
第04节 Lambda和匿名内部类
说明
-
区别一:引用简化方式不同。
A. 匿名内部类,他可以作用于 接口或者是类
B. Lambda表达式, 他只能作用于函数式接口
-
区别二: 底层实现不同。
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);
}
第02节 常用API
获取流的操作
常用方法
说明:
终结:操作完毕之后,不再是 Stream 流对象。
中间:操作完毕之后,还是 Stream流对象,还可以继续调用 Stream流当中的方法。
收集:操作完毕之后,可以将 Stream流转换成为集合对象。