[elegant code] 14 guava selection method and source code analysis of eventBus observer mode
Welcome to b station official account / public number [hexagon warrior Xia Ning], a man who wants to fill all the indicators. The article has been published in github directory Included.
The handsome and beautiful in front of the screen, if it helps you, please like it and add a collection, which is really important to me. Don't worry about where you go next time.
- Video Explanation
- Complete code that can be run directly
- Last Is linkedList really faster to insert than arrayList
- Next guavaCache local cache usage and source code analysis
1. Background
google's guava is a very classic tool class, but after years of development of java, many methods have excellent alternatives. The following is a very classic method that I still feel in my daily development.
2. Basic tools
Because of the popularity of Optional and stream, the methods in this tool class are basically useless.
3. Collections (important)
This section mainly introduces the collection of guava. Although the tool class is a supplement to apache, it is too fancy.
3.1 immutable set
- General usage
public static void immutableOrdinary() { // General creation Set<Integer> set = ImmutableSet.of(1, 2, 3, 1); List<Integer> list = ImmutableList.of(1, 2, 3, 1); // The k-v continuous writing method of map is still very comfortable Map<Integer, Integer> map = ImmutableMap.of(1, 2, 3, 1); // Loop creation ImmutableSet.Builder<Integer> builder = ImmutableSet.<Integer>builder(); for (int i = 0; i < 10; i++) { builder.add(i); } Set<Integer> build = builder.build(); // The general list is immutable. It is worth noting that collections unmodifiableList() List<Integer> collect = Stream.of(1, 2, 3, 4).collect(Collectors.toList()); List<Integer> integers = ImmutableList.copyOf(collect); }
- Insert performance comparisons in almost the same way
public static void effectiveList() { StopWatch sw = new StopWatch(); sw.start("listAdd"); Stream.Builder<Integer> builder1 = Stream.builder(); for (int i = 0; i < 10000; i++) { builder1.add(i); } List<Integer> list = builder1.build().collect(Collectors.toList()); sw.stop(); sw.start("ImmutableListAdd"); ImmutableList.Builder<Integer> builder = ImmutableList.builder(); for (int i = 0; i < 10000; i++) { builder.add(i); } List<Integer> guava = builder.build(); sw.stop(); System.out.println(sw.prettyPrint()); }
- You can see that the immutable set with obvious insertion speed is faster
--------------------------------------------- ns % Task name --------------------------------------------- 072909616 081% listAdd 017632120 019% ImmutableListAdd
- Get the speed comparison of a single element
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 is too slow. The other two are almost as efficient. guava still needs to be faster
--------------------------------------------- 000018405 089% listGet 000001323 006% listUnGet 000000936 005% guavaGet
- Cycle performance comparison
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();
- Consistent with the above results
--------------------------------------------- 007031946 053% listFor 003760153 028% listUnFor 002458426 019% guavaFor
As mentioned above, this is why I like guava very much
5. Difference and comparison
// The general list is immutable. It is worth noting that collections Unmodifiablelist() if the original list is changed, it will be changed list.remove(0); // That is, list and unmodifiableList will be one less
3.2 new set type
public static void newCollections(){ // Only BiMap and Table are introduced here. Multiset and Multimap are embedded in the list BiMap<Integer,String> biMap=HashBiMap.create(); biMap.put(1,"Zhang San"); biMap.put(2,"Li Si"); biMap.put(3,"Wang Wu"); biMap.put(4,"Zhao Liu"); biMap.put(5,"Li Qi"); biMap.put(6,"Little"); Integer result = biMap.inverse().get("Zhao Liu"); // Output result 4 System.out.println(result); // =========================================================== // table is a very interesting data structure and enlightening thinking, although I don't know what use it is /* * 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"); //All row data System.out.println(employeeTable.cellSet()); //All companies System.out.println(employeeTable.rowKeySet()); //All employee numbers System.out.println(employeeTable.columnKeySet()); //Name of all employees System.out.println(employeeTable.values()); //All employees and employee numbers in the company System.out.println(employeeTable.rowMap()); //Company and employee name corresponding to employee number System.out.println(employeeTable.columnMap()); }
The output is as follows
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 collection tools
public static void Collections() { // Personally, I think the following methods are used. The first ones can be regarded as the memory implementation of redis intersection and union. The latter is the memory implementation of Cartesian product of database // Intersection, union Set<Integer> set1 = Stream.of(1, 2, 3, 4).collect(Collectors.toSet()); Set<Integer> set2 = Stream.of(3, 4, 5, 6).collect(Collectors.toSet()); // Find the difference set of set1 System.out.println(Sets.difference(set1, set2)); // Find the union of set1 and set2 difference sets System.out.println(Sets.symmetricDifference(set1, set2)); // Find intersection System.out.println(Sets.intersection(set1, set2)); // Cartesian product System.out.println(Sets.cartesianProduct(set1, set2)); // Cartesian product 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)); }
The output is as follows
[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]]
4. Cache (important)
This part will be shared separately in the next article.
5. Functional idioms
Like 2, it is not used much under the strong action of stream
6. Concurrency
The future part already has a completable future (introduced in Section 4 thread), which is very easy to use. Some of the functions of Service are very powerful, but they are generally not used.
The current limiting part will be shared in the next chapter
7. String processing Strings
apache is not bad either. This one is almost the same
8. Primitive types
The function looks great, but no actual use scenario has been found yet
9. Interval Ranges
The function looks great, but no actual use scenario has been found yet
10.I/O
apache's IOUtils are simpler to use than this
11. Hash (business specific)
The bloom filter provided in this can still be used when there are scenes in need. Hash algorithm also has a place in dealing with file consistency verification.
This part will be shared separately in the next article.
12. Event bus eventbus (important)
Super easy observer mode, useful can use this thing, write a lot more comfortable. I like the design idea of this piece very much and feel it necessary to expand it. It should be noted that @ Subscribe will be notified only if the method parameters are consistent with the delivered object parameters.
12.1 code usage
- Create observer
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"); } }
- Method notification
public static void eventBus() { EventBus eventBus = new EventBus("eventBusTest"); eventBus.register(new eventBusObject()); eventBus.post(100); eventBus.post("I'm a string"); }
- Output results
100listenInt1 100listenStr1 I'm a string listenStr1 I'm a string listenStr2 I'm a string listenStr1
12.2 core source code
- register
// Click to enter register. The method is as follows public void register(Object object) { subscribers.register(object); } // Click again to enter the register. The method is as follows. Here it is mainly reflection, and then it is saved void register(Object listener) { // The core method reflects the method to get @ Subscribe the annotation, and classifies the incoming 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); } eventSubscribers.addAll(eventMethodsInListener); } }
- call
// Main method call post public void post(Object event) { // This method conforms to the iterative set of 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 post(new DeadEvent(this, event)); } } // The main method calls the getSubscribers method Iterator<Subscriber> getSubscribers(Object event) { // This method returns all the parent objects of event. The top level is Object. The following is to take the intersection of the two for assembly 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 subscriberIterators.add(eventSubscribers.iterator()); } } return Iterators.concat(subscriberIterators.iterator()); } // Return to the main method dispatcher Dispatch is called, and the method is marked as 2.1 @Override void dispatch(Object event, Iterator<Subscriber> subscribers) { checkNotNull(event); checkNotNull(subscribers); Queue<Event> queueForThread = queue.get(); queueForThread.offer(new Event(event, subscribers)); if (!dispatching.get()) { dispatching.set(true); try { Event nextEvent; while ((nextEvent = queueForThread.poll()) != null) { while (nextEvent.subscribers.hasNext()) { // Core method call, marked 2.1.1 nextEvent.subscribers.next().dispatchEvent(nextEvent.event); } } } finally { dispatching.remove(); queue.remove(); } } } // From 2.1.1, you can see that the task is directly thrown into the thread pool 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)); } } }); }
13. Mathematical operation Math
Generally, it is not used. There are Math packages under apache, and the functions are basically the same
14. Reflection (less important)
Spring also brings this tool class. Personally, I feel that spring has been very excellent in dealing with routine cases. The generic direction is added here, which is relatively simple to use. However, in view of the few opportunities for ordinary use, it will not be expanded.