浅学JAVA泛型二:泛型在项目中的简单应用
前言:
阅读本章内容,你可以学到如下知识:
- 泛型在处理集合中的简单应用
- 泛型封装通用方法的简单应用
- 泛型在设计模式中的应用
一丶泛型在处理集合中的简单应用
泛型:具体的类型参数化,在具体传入或者调用时才去传入具体的类型。(指定容器要持有什么类型的对象,由编译器保证类型的正确性)
1. 前段时间开发项目,有一个需求的要获取历史的数据获取到最后一条,第三方系统的接口会返回最近的五条历史数据集合,所以我需要在代码中获取最后一个元素。
- 先给出不用泛型的写法:
public static BaseResponse getLastElement(List<BaseResponse> list){
Assert.isTrue(CollectionUtils.isNotEmpty(list), "Collection is invalid.");
return list.get(list.size() -1);
}
上面的代码可以实现获取最后一个元素的需求,但是如果我们下次如果还有一个获取最后一个元素的需求,我们就需要再重写一个这样的方法,其实我们这里可以使用泛型这样无论传入什么样的数据都可以实现获取最后一个元素的需求。
- 使用泛型的写法
public static <T> T getLastElement(List<T> list){
AssertUtils.isTrue(CollectionUtils.isNotEmpty(list), "Collection is invalid.");
return list.get(list.size() -1);
}
2. 我们在工作中可能还会遇到求两个集合交集的需求,我们也可以使用泛型来创造一个通用的方法
private <T> List<T> mergeList(List<T> original, List<T> list) {
if (CollectionUtils.isEmpty(original)) {
return list;
}
original.retainAll(list);
return original;
}
二丶泛型封装方法的简单应用
其实上面泛型在处理集合时的简单应用也就相当于泛型封装方法的简单应用,所以我们在这章就介绍泛型结合函数式编程的用法
- 先简单介绍下函数编程
函数式编程:它把计算过程当做是数学函数的求值,而避免更改状态和可变数据,在我们java代码中的体现就是将函数作为方法的参数来进行传递(结合jdk8的Lambda表达式进行使用)。
- 回顾一下Jdk8提供的四个函数式编程的接口
接口名 接收参数 返回值 注释 Predicate<T>
T boolean (断言型接口)用于判别一个对象是否是某个状态。比如球是不是园的 Consumer<T>
T void (消费型接口)用于接收一个对象进行处理但没有返回,比如银行收到你的钱在你的账单上记一笔 Function<T, R>
T R (函数型接口)转换一个对象为不同类型的对象 Supplier<T>
None T (供给型接口)不传入参数返回一个对象
我们以我们上篇文章# 浅学JAVA泛型一:泛型的基础知识的第二例子举例。
public class Main {
@Test
public void test() {
String messageContent = "[message]:泛型真好用";
String commentContent = "[comment]:泛型真好用";
Message message = new Message();
Comment comment = new Comment();
execute(messageContent, message::setContent);
execute(commentContent, comment::setContent);
System.out.println(message.getContent()); // [message]:泛型真好用
System.out.println(comment.getContent()); // [comment]:泛型真好用
}
private <T> void execute(T t, Consumer<T> consumer) {
consumer.accept(t);
}
}
class Message {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
class Comment {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
在上面代码中我们重点看
execute
传入了一个泛型和一个Consumer
函数,我们这个方法就可以传入任意类型,然后再传入一个需要一个参数无返回值的方法进行使用,并且可以使用函数表达式进行书写代码。
三丶泛型在设计模式中的应用
我们以观察者模式来举例
首先大概介绍一下观察者模式
观察对象的状态发生变化,通知观察者做出对应操作
观察者模式主要有四个角色
- Subject(观察对象):Subject角色表示观察对象。Subject角色定义了注册观察者和删除观察者的方法。此外,它还声明了“获取现在的状态”的方法。
- ConcreteSubject(具体的观察对象):ConcreteSubject角色表示具体的被观察对象。当自身状态发生变化后,它会通知所有已经注册 的Observer角色。
- Observer(观察者):Observer角色负责接收来自Subject角色的状态变化的通知。为此,它声明了update方法。
- ConcreteObserver(具体的观察者):ConcreteObserver角色表示具体的Observer。当它的update方法被调用后,会去获取要观察的对象的最新状态。
观察者:
public interface Observer {
void update();
}
具体的观察者:
public class PassObserver implements Observer {
@Override
public void update() {
// Pass具体的操作
}
}
public class OutObserver implements Observer {
@Override
public void update() {
// Out具体的操作
}
}
观察对象
public abstract class Subject<T> {
private Observer observer;
public void setObserver(Observer observer){
this.observer = observer;
}
public void natifuObserver(){
observer.update();
}
public abstract void execute(T t);
}
具体的观察对象
public class ReviewSubject extends Subject<String> {
@Override
public void execute(String str) {
System.out.println(str);
this.natifuObserver();
}
}
使用: `public class Main {
@Test
public void test() {
ReviewSubject reviewSubject = new ReviewSubject();
reviewSubject.set(new PassObserver());
reviewSubject.execute("你通过了");
}
}`
我们可以看到上图的观察者模式里面观察者对象是一个泛型类,我们可以指定任意的类型进行观察然后做出不同的处理,如果我们指定一个固定的对象就没有办法做到通用了。
总结
从上面的几个例子中我们可以发现我们想要写出通用性强的代码学习使用泛型是必不可少的,希望大家可以get到泛型的使用
摘要:设计模式概念部分摘抄自<<图解设计模式>>
转载自:https://juejin.cn/post/7135438542506819592