# 【优雅代码】14-guava精选方法及eventBus观察者模式源码解析

2022年01月14日 阅读数：0

# 【优雅代码】14-guava精选方法及eventBus观察者模式源码解析

## 3.集合Collections(重要)

### 3.1不可变集合

1. 常规用法
``````public static void immutableOrdinary() {
// 常规建立
Set<Integer> set = ImmutableSet.of(1, 2, 3, 1);
List<Integer> list = ImmutableList.of(1, 2, 3, 1);
// map的k-v连续的写法仍是很是舒服的
Map<Integer, Integer> map = ImmutableMap.of(1, 2, 3, 1);

// 循环建立
ImmutableSet.Builder<Integer> builder = ImmutableSet.<Integer>builder();
for (int i = 0; i < 10; i++) {
}
Set<Integer> build = builder.build();

// 常规list转不可变,值得注意的是Collections.unmodifiableList()
List<Integer> collect = Stream.of(1, 2, 3, 4).collect(Collectors.toList());
List<Integer> integers = ImmutableList.copyOf(collect);
}
``````
1. 以近乎一样的方式插入性能对比
``````public static void effectiveList() {
StopWatch sw = new StopWatch();
Stream.Builder<Integer> builder1 = Stream.builder();
for (int i = 0; i < 10000; i++) {
}
List<Integer> list = builder1.build().collect(Collectors.toList());
sw.stop();

ImmutableList.Builder<Integer> builder = ImmutableList.builder();
for (int i = 0; i < 10000; i++) {
}
List<Integer> guava = builder.build();
sw.stop();
System.out.println(sw.prettyPrint());
}
``````
• 能够看到插入速度很是明显的不可变集合要更快
``````---------------------------------------------
---------------------------------------------
``````
1. 获取单个元素的速度对比
``````List<Object> listUn = Collections.unmodifiableList(list);
sw.start("listGet");
list.get(0);
sw.stop();
sw.start("listUnGet");
listUn.get(0);
sw.stop();
sw.start("guavaGet");
guava.get(0);
sw.stop();
``````
• list可太慢了，其它两个效率差很少,guava仍是要更快一点
``````---------------------------------------------
000018405  089%  listGet
000001323  006%  listUnGet
000000936  005%  guavaGet
``````
1. 循环性能对比
``````List<Object> listUn = Collections.unmodifiableList(list);
sw.start("listFor");
IntStream.range(0, 10000).boxed().forEach(list::get);
sw.stop();
sw.start("listUnFor");
IntStream.range(0, 10000).boxed().forEach(listUn::get);
sw.stop();
sw.start("guavaFor");
IntStream.range(0, 10000).boxed().forEach(guava::get);
sw.stop();
``````
• 和上面的结果一致
``````---------------------------------------------
007031946  053%  listFor
003760153  028%  listUnFor
002458426  019%  guavaFor
``````

5. 区别对比算法

``````// 常规list转不可变,值得注意的是Collections.unmodifiableList()若是原list被改变不可变是会被改变的
list.remove(0);
// 即list和unmodifiableList都会少一个
``````

### 3.2新集合类型

``````public static void newCollections(){
// 这里只介绍BiMap和Table。Multiset、Multimap这两个就是嵌了list进去
BiMap<Integer,String> biMap=HashBiMap.create();
biMap.put(1,"张三");
biMap.put(2,"李四");
biMap.put(3,"王五");
biMap.put(4,"赵六");
biMap.put(5,"李七");
biMap.put(6,"小小");
Integer result = biMap.inverse().get("赵六");
// 输出结果4
System.out.println(result);
// ===========================================================
// table是个颇有意思的数据结构，颇有启发性思惟，虽然我也不知道这个有啥用
/*
*  Company: IBM, Microsoft, TCS
*  IBM         -> {101:Mahesh, 102:Ramesh, 103:Suresh}
*  Microsoft     -> {101:Sohan, 102:Mohan, 103:Rohan }
*  TCS         -> {101:Ram, 102: Shyam, 103: Sunil }
*
* */
//create a table
Table<String, String, String> employeeTable = HashBasedTable.create();

//initialize the table with employee details
employeeTable.put("IBM", "101","Mahesh");
employeeTable.put("IBM", "102","Ramesh");
employeeTable.put("IBM", "103","Suresh");

employeeTable.put("Microsoft", "111","Sohan");
employeeTable.put("Microsoft", "112","Mohan");
employeeTable.put("Microsoft", "113","Rohan");

employeeTable.put("TCS", "121","Ram");
employeeTable.put("TCS", "102","Shyam");
employeeTable.put("TCS", "123","Sunil");

//全部行数据
System.out.println(employeeTable.cellSet());
//全部公司
System.out.println(employeeTable.rowKeySet());
//全部员工编号
System.out.println(employeeTable.columnKeySet());
//全部员工名称
System.out.println(employeeTable.values());
//公司中的全部员工和员工编号
System.out.println(employeeTable.rowMap());
//员工编号对应的公司和员工名称
System.out.println(employeeTable.columnMap());
}
``````

``````4
[(IBM,101)=Mahesh, (IBM,102)=Ramesh, (IBM,103)=Suresh, (Microsoft,111)=Sohan, (Microsoft,112)=Mohan, (Microsoft,113)=Rohan, (TCS,121)=Ram, (TCS,102)=Shyam, (TCS,123)=Sunil]
[IBM, Microsoft, TCS]
[101, 102, 103, 111, 112, 113, 121, 123]
[Mahesh, Ramesh, Suresh, Sohan, Mohan, Rohan, Ram, Shyam, Sunil]
{IBM={101=Mahesh, 102=Ramesh, 103=Suresh}, Microsoft={111=Sohan, 112=Mohan, 113=Rohan}, TCS={121=Ram, 102=Shyam, 123=Sunil}}
{101={IBM=Mahesh}, 102={IBM=Ramesh, TCS=Shyam}, 103={IBM=Suresh}, 111={Microsoft=Sohan}, 112={Microsoft=Mohan}, 113={Microsoft=Rohan}, 121={TCS=Ram}, 123={TCS=Sunil}}
``````

### 3.3集合工具类

``````public static void Collections() {
// 我的以为比较又用的有以下几个方法，前几个能够看作是redis交集、并集的内存实现。后面是数据库笛卡尔积的内存实现
// 交集、并集、
Set<Integer> set1 = Stream.of(1, 2, 3, 4).collect(Collectors.toSet());
Set<Integer> set2 = Stream.of(3, 4, 5, 6).collect(Collectors.toSet());
// 求set1的差集
System.out.println(Sets.difference(set1, set2));
// 求set1和set2差集的并集
System.out.println(Sets.symmetricDifference(set1, set2));
// 求交集
System.out.println(Sets.intersection(set1, set2));
// 笛卡尔积
System.out.println(Sets.cartesianProduct(set1, set2));

// 笛卡尔积
List<Integer> list1 = Stream.of(1, 2, 3, 4).collect(Collectors.toList());
List<Integer> list2 = Stream.of(2, 3, 4, 5).collect(Collectors.toList());
System.out.println(Lists.cartesianProduct(list1, list2));
}
``````

``````[1, 2]
[1, 2, 5, 6]
[3, 4]
[[1, 3], [1, 4], [1, 5], [1, 6], [2, 3], [2, 4], [2, 5], [2, 6], [3, 3], [3, 4], [3, 5], [3, 6], [4, 3], [4, 4], [4, 5], [4, 6]]
``````

## 7.字符串处理Strings

apache的也不差，这块都差很少

## 10.I/O

apache的IOUtils用起来比这个要简单

## 12.事件总线EventBus(重要)

### 12.1代码使用

1. 建立被观察者
``````public static class eventBusObject {
@Subscribe
public void listenStr1(String str) {
System.out.println(str + "listenStr1");
}

@Subscribe
public void listenStr2(String str) {
System.out.println(str + "listenStr2");
}

@Subscribe
public void listenObj(Object str) {
System.out.println(str + "listenStr1");
}

@Subscribe
public void listenInt1(Integer str) {
System.out.println(str + "listenInt1");
}

public void listenInt2(Integer str) {
System.out.println(str + "listenInt2");
}
}
``````
1. 方法通知
``````public static void eventBus() {
EventBus eventBus = new EventBus("eventBusTest");
eventBus.register(new eventBusObject());
eventBus.post(100);
eventBus.post("我是字符串");
}
``````
1. 输出结果
``````100listenInt1
100listenStr1

``````

### 12.2核心源码

1. 注册
``````// 点击进入register方法以下
public void register(Object object) {
subscribers.register(object);
}
// 再点击进入register方法以下,这里主要是反射，而后就存起来
void register(Object listener) {
// 核心方法反射获取@Subscribe该注解的方法，并将传入的class进行分类
Multimap<Class<?>, Subscriber> listenerMethods = findAllSubscribers(listener);

for (Entry<Class<?>, Collection<Subscriber>> entry : listenerMethods.asMap().entrySet()) {
Class<?> eventType = entry.getKey();
Collection<Subscriber> eventMethodsInListener = entry.getValue();

CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);

if (eventSubscribers == null) {
CopyOnWriteArraySet<Subscriber> newSet = new CopyOnWriteArraySet<>();
eventSubscribers =
MoreObjects.firstNonNull(subscribers.putIfAbsent(eventType, newSet), newSet);
}

}
}
``````
1. 调用
``````// 主方法调用post
public void post(Object event) {
// 该方法反符合event的迭代集合
Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
if (eventSubscribers.hasNext()) {
dispatcher.dispatch(event, eventSubscribers);
} else if (!(event instanceof DeadEvent)) {
// the event had no subscribers and was not itself a DeadEvent
}
}

// 主方法调用getSubscribers方法
Iterator<Subscriber> getSubscribers(Object event) {
// 该方法返回event全部的父级对象，最上级即为Object，下面就是取二者交集进行组装
ImmutableSet<Class<?>> eventTypes = flattenHierarchy(event.getClass());

List<Iterator<Subscriber>> subscriberIterators =
Lists.newArrayListWithCapacity(eventTypes.size());

for (Class<?> eventType : eventTypes) {
CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);
if (eventSubscribers != null) {
// eager no-copy snapshot
}
}

return Iterators.concat(subscriberIterators.iterator());
}
// 回到主方法dispatcher.dispatch进行调用，该方法标记为2.1
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
checkNotNull(event);
checkNotNull(subscribers);

if (!dispatching.get()) {
dispatching.set(true);
try {
Event nextEvent;
while ((nextEvent = queueForThread.poll()) != null) {
while (nextEvent.subscribers.hasNext()) {
//  核心方法调用，标记为2.1.1
nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
}
}
} finally {
dispatching.remove();
queue.remove();
}
}
}
// 从2.1.1这里就能够看到把任务直接丢到线程池
final void dispatchEvent(final Object event) {
executor.execute(
new Runnable() {
@Override
public void run() {
try {
invokeSubscriberMethod(event);
} catch (InvocationTargetException e) {
bus.handleSubscriberException(e.getCause(), context(event));
}
}
});
}
``````

## 14.反射Reflection(次重要)

spring里面也带了这块的工具类，我的感受spring的在处理常规状况下已经很是优秀了，这边补充了泛型方向的，用起来也比较简单，不过鉴于日常使用的机会很少就不展开了。