Java学习笔记4(设计模式、接口)

设计模式 - 建造者模式

  1. 在类中,定义一个静态内部类作为 外部类的 建造者
  2. 在建造者类中,提供多个 方法用来完成 外部类 对象的属性赋值
  3. 在建造者类中,提供一个 build() 用来返回一个外部类的对象
  4. 在类中,通常定义一个静态的 builder() 来返回一个 建造者对象

将 对象的 属性(特征) 和 方法(行为)进行一个分离
对象中的属性交由建造者进行管理
对象中的方法由自己来调用

Lombok

对模板化代码进行快速生成的插件
在工程中引入 Lombok.jar

Lombok常用注解

  • @Getter

用来生成对应的 get方法、可以写在类上 或者 属性上

  • @Setter

用来生成对应的 set方法、可以写在类上 或者 属性上

  • @ToString

用来生成类中的 toString方法, 只能应用于 类上

  • @EqualsAndHashCode

用来生成类中的 equals 和 hashCode 方法, 只能应用于类上

  • @Data

等价于在类上,同时使用 @Setter, @Getter, @ToString, @EqualsAndHashCode

  • @NoArgsConstructor

用来在类上 快速生成无参构造

  • @AllArgsConstructor

用来在类上,快速生成 带有 所有参数的构造方法,参数的顺序由 在类上属性的定义顺序来决定

  • @RequiredArgsConstructor

配合 @NonNull(非空注解), 来定义指定参数的构造方法, 将所有的 @NonNull 注解的Field属性 作为 构造方法的参数

  • @Builder

用来给 当前标记的类 提供 建造者模式

一般情况下,如果类中使用了 @Builder 注解, 那么 无参构造就不会被提供,所以通常情况下使用 @Builder注解,推荐使用 @Data, @NoArgsConstructor, @AllArgsConstructor
如果类中不需要建造者模式,那么一般推荐使用 @Data 注解

  • @Builder.Default

给属性设置默认值,如果使用了@Builder , 那么 属性中的默认值默认在建造者模式下不会生效,如果希望生效,则需要在属性前面添加 @Builder.Default

接口

接口是一种规范和标准, 用关键字 interface 标识接口
接口是一种特殊的抽象类
接口中所有的属性 都是 public static final 修饰的 (公开静态常量)
接口中的方法在 JDK7 以及一下版本,都是 公开 抽象方法
接口可以提高程序的可扩展性、降低程序之间的耦合度(低耦合高内聚)
一个类可以实现多个接口 (接口和类之间采用 多实现,使用 implements 关键字 )
接口描述的是一个对象 有没有 能力
接口与接口之间采用 多继承、使用 extends 关键字

接口 VS 类

  • 接口 使用 interface 修饰, 类使用 class修饰
  • 类是描述一个具有相同特征和行为的事物统称、接口是描述一种规范和标准
  • 接口与接口采用 多继承、接口和类采用多实现,而类与类采用单继承
  • 类中可以由 代码块,构造方法、方法、属性、内部类
  • 接口中不能有 代码块 和 构造方法
  • 类可以创建对象、接口不能,接口需要对应的子类去构建对象

接口 VS 抽象类

  • 接口中属性都是 public static final 修饰的, 而 抽象类中的属性 没有要求
  • 接口中的方法(JDK7)都是抽象方法, 而抽象类中 可以没有抽象方法
  • 接口中没有构造方法,而抽象类中有构造方法
  • 接口与接口采用 多继承、接口和类采用多实现,而类与类采用单继承

JDK8 接口的语法

  • 允许在接口中定义 default 修饰的成员方法, 主要解决接口中定义的多个方法重载复用的问题
  • 允许在接口中定义 public static 修饰的 方法

JDK9 接口的语法

  • 允许在接口中定义 private 修饰的成员方法,主要解决 default 修饰的成员方法 代码复用问题

JDK8 函数式接口 FunctionInterface

如果一个接口有且只有一个 抽象方法(不包含Object中定义的方法),那么这个接口就被称为函数式接口
如果一个接口是函数式接口,则可以使用一个注解 @FunctionalInterface 标记
如果一个接口是函数式接口 , 那么这个接口可以使用 Lambda 表达式 快速构建接口的子类对象

Lambda表达式

Lambda 表达式的语法:

  1. (参数列表) -> {… 方法的具体实现代码… }
  2. lambda表达式返回的是 该接口的子类对象

参数列表:

  1. 如果 没有参数, 则只需要写一个 () 即可
  2. 如果 有参数 ,括号中参数类型 可以省略
  3. 如果只有一个参数,可以在省略类型后,再省略 小括号

方法实现:

  1. 如果 实现代码只有一个语句 、则可以省略 { … }
  2. 如果省略大括号后,代码中包含 return ,则 必须省略 return

Comparable 接口

可比较, 如果一个类希望它的对象能够进行比较大小, 那么这个类就可以实现 Comparable接口,重写 compareTo(T obj) 方法
compareTo 返回一个 int ,如果 大于0 ,代表 调用者 大, 如果等于0,代表 一样大, 如果小于0,代表 被比较的对象大

Comparator 接口

用来比较2个对象的大小,即使对象没有实现 Comparable接口,也可以进行大小的比较
int compare(T o1, T o2) 抽象方法,是专门用来 制定比较对象大小的 标准


 // 3月份生日,固定薪资4000
SalariedEmployee salariedEmployee = new SalariedEmployee("张三", 3, 4000);
// 4月生日,时薪 50
HourlyEmployee hourlyEmployee = new HourlyEmployee("李四", 4, 175, 50);

// 如果 对象没有实现 Comparable接口,那么默认是不能比较大小的 ,但是 可以通过 Comparator 接口制定比较规则
int month = 3;
Comparator<Employee> comparator = (a, b) -> {
    double as = a.getSalary(month);
    double bs = b.getSalary(month);
    if (as > bs) return 1;

    if (as == bs) return 0;

    return -1;
} ;

// 比较两个员工薪资的高低 
int compare = comparator.compare(salariedEmployee, hourlyEmployee);

System.out.println(compare);

  • Comparator.reverseOrder() : 返回一个 Comparator 对象, 按照对象的默认提供的排序规则的相反规则进行比较,前提是对象所在的类必须实现Comparable 接口
  • Comparator.naturalOrder() : 返回一个 Comparator 对象,按照对象的默认比较规则,前提是对象所在的类必须实现Comparable 接口

public static void sort(Employee[] employee, Comparator comparator) {

}

Iterable

可迭代的, 如果一个类的对象希望能够被循环遍历,那么可以让这个类实现 Iterable 接口
重写 Iterable 接口中 的 iterator 方法,返回一个 迭代器
如果一个实现了Iterable 接口 ,那么就可以拥有 iterator遍历、 增强for循环、 forEach

Iterator

迭代器中有2个重要的抽象方法
hasNext() : 用来判断是否有下一个数据
next() : 用来获取下一个数据、并将索引 + 1

函数式接口的分类

函数式接口 对象的创建 可以通过 lambda表达式 , 它还支持 方法的引用,语法式 ::
方法引用: 在程序中,刚好有一个方法能够满足 函数式接口中抽象方法的实现要求,那么此时就可以通过 :: 的方式引入这个方法
作为 函数式接口中抽象方法的具体代码实现

  • 消费型接口

函数式接口中的抽象方法,只有参数,没有返回值(void), 那么该接口就被称为 消费型接口
Consumer : 消费一个参数
BiConsumer : 消费二个参数

// 构建一个Consumer的子类对象,负责将消费的数据 打印出来 
Consumer consumer = a -> System.out.println(a) ; 

成员方法 和 静态方法 

成员方法 使用 对象 来进行调用 ------>  对象::方法
静态方法 使用 类 来进行调用  ------>   类::方法

类:: 静态方法
类:: 成员方法 ----> 如果类引用成员方法,那么成员方法相当于默认第一个参数 是 类对应的对象 

打印语句是一个 消费者 
System.out.println("xxxxx") ; 
Consumer con = System.out::println

  • 生产型接口

抽象方法 没有参数,但有返回值
Supplier :

如何引用无参构造方法: 类型::new即可实现引用无参构造作为生产者对应的抽象方法的具体实现代码

Supplier<Car> sup = Car::new ; 

Car car = sup.get();
  • 功能型接口

既是生产者、又是消费者的函数式接口,被称为功能型接口
接口中的抽象方法,既有参数又有返回值

Function<T, R> : 消费一个 T, 返回一个 R
BiFunction<T, U, R> : 消费一个 T 和 U , 返回一个 R

BiFunction<Integer, Integer, Integer>  fn = Integer::sum ; 
int x = fn.apply(3, 6) ; // 9   

Function<Double, Double> f = Math::sqrt; 
double x = f.apply(25)  // 5
  • 断言型接口

是一个特殊的功能型接口, 生产的一定是 boolean 类型

Predicate : 消费一个 T, 返回一个 boolean
BiPredicate<T, U> : 消费一个 T 和 U , 返回一个 boolean

函数式接口在API中的应用

  • Stream 流式处理 : 主要用来处理数据的, 整个流式处理不会影响原有的数据

开始流 : 如何将数据转成流
中间流 : 对数据进行加工和处理
终止流 : 结束整个流式处理、完成对数据的组装

如何将数据(数组)转成流

  • IntStream stream = Arrays.stream(array) 将数组转成stream流
  • IntStream stream = Arrays.stream(array, start, end) 将数组指定的区间内的数据转成Stream流
  • IntStream.of(val…) : 将多个值转成 stream 流

常见的中间流

所有的中间流,默认都采用延迟加载,只有在调用终止流的时候,中间流才会执行对应的代码

  • map(IntUnaryOperator mapper) : IntUnaryOperator 是一个功能型接口,消费一个 int , 返回一个 int

只对流中的数据做修改,不会影响 流中数据的 类型 和 个数

  • mapToLong(IntToLongFunction mapper) : IntToLongFunction 是一个功能型接口,消费一个 int , 返回一个 long

只对流中的数据做修改,不会影响 流中数据的个数, 但流中数据的类型会发生改变

  • mapToDouble(IntToDoubleFunction mapper): IntToDoubleFunction是一个功能型接口,消费一个 int , 返回一个 double

只对流中的数据做修改,不会影响 流中数据的个数, 但流中数据的类型会发生改变

  • mapToObj(DoubleFunction<? extends U> mapper) : 消费一个数字, 返回一个任意的数据类型

只对流中的数据做修改,不会影响 流中数据的个数, 但流中数据的类型会发生改变

  • filter(Predicate predicate) : 过滤满足条件的数据,返回 0 ~ N个值

会将不满足条件的数据过滤掉,流中剩下的数据都是满足条件的数据,流中的数据个数可能会减少, 但对应的数据内容 不会发生任何变化

  • distinct() : 对流中的数据 进行去重

  • skip(n) : 跳过前面 n 个数据

  • dropWhile(Predicate predicate) : 删除满足条件的数据,直到不满足为止, JDK9

  • takeWhile(Predicate predicate) : 保留满足条件的数据、直到不满足为止, JDK9

  • peek(Consumer consumer) : 和 forEach用法类似,但peek是一个中间流,主要用来观察数据在流中的状态

常见的终止流

  • toArray(): 将流中的数据放入到数组中

  • max() : 获取数组中的最大值

  • min() : 获取数组中的最小值

  • sum() : 获取数组中元素的和

  • average() : 获取数组中元素的平均值

  • count() : 获取流中元素的个数

  • forEach() : 遍历流中的元素

  • allMatch(Predicate predicate) : 断言流中的数据全部满足指定的条件, 返回boolean

  • anyMatch(Predicate predicate) : 断言流中有元素满足指定的条件, 返回boolean

  • noneMatch(Predicate predicate) : 断言流中的所有元素全部不满足指定的条件, 返回boolean

  • findAny() : 获取 流中的一个元素, 主要应用于多线程环境

  • findFirst() : 获取 流中的第一个元素

  • int reduce(int identity, IntBinaryOperator op) : 用来进行统计

identity : 进行统计的结果的初始值
IntBinaryOperator : 消费两个参数 以 a, b 为例子 a 代表 上一轮统计的结果,如果是第一次进来,那么 a 会取 identity 作为初始值
b 代表 本轮要统计的数据、如果是第一次进来,则默认是 流中的 第一个数据, IntBinaryOperator 生产一个数据,生产的数据作为本轮统计的结果
会自动赋值给下一轮中的 a 作为值 下一轮 a 的初始值

  • int reduce(IntBinaryOperator op) : 用来进行统计

IntBinaryOperator : 消费两个参数 以 a, b 为例子 a 代表 上一轮统计的结果,如果是第一次进来,那么 a 会取 流中的第一个值作为初始值
b 代表 本轮要统计的数据、如果是第一次进来,则默认是 流中的 第二个数据, IntBinaryOperator 生产一个数据,生产的数据作为本轮统计的结果
会自动赋值给下一轮中的 a 作为值 下一轮 a 的初始值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值