preface

Only a bald head can be strong

I have been learning Redis for a while, but I was abused in the golden section, and I can’t get the first win every day.

Taking advantage of the school sports meet, reasonable to put a small holiday, and then went home. Return home just discover 618 bought a pile of books at that time, this pile of books still have not tore package…. So I dug out the thinnest “Alibaba Java Development Manual.”

The book has more than 90 pages, so I could read it all in one day.

Note:

  • There are many specifications in the book that can be avoided using an IDE, and many that are already known.
  • So, this article will only document some of the specifications that I think are important, or that I didn’t notice in my previous development.
  • The content of this article is certainly not as complete as written in the book, if you are interested in it, you can buy a copy and read it

PDF Official address:

  • github.com/alibaba/p3c

First, Java related

  1. POJO is a general name of DO, DTO, BO, and VO. DO not name it xxxPOJO
  2. Methods that get multiple objects are prefixed with list
  3. Methods that get statistics are prefixed with count
  4. POJO class Boolean variables should not be prefixed with is, otherwise partial framework parsing will cause serialization errors
    • If your variable name has is in it, such as isActive, the framework may parse it as active.
  5. If the interface name describes the capability, use the corresponding adjective as the interface name (usually in the form of -able).
  6. No mana values (non-predefined constants) are allowed to appear directly in code
  7. Object’s euqals method tends to throw a null pointer exception. Call equals using a constant or a valued Object. It is recommended to usejava.util.Object#equalsUtility class
  8. All the POJOAttributes of a classAll useWrapper data typeRPC return values and parameters must be usedpackagingData types, all of themA local variableAll useThe basic dataType. When defining POJO classes such as VO/DTO/DO, DO not set default values for any properties
    • If your class attribute uses a primitive data type such as int, the default value is 0. In general, this variable is not assigned, and you want to say that there is no value (null), not 0.
  9. The constructor disallows any business logic if the initialization logic can be placed in the init method. Set/GET methods also do not add business logic.
    • If the set/get methods are put into the business logic, troubleshooting sometimes becomes cumbersome
  10. The arrays.asList () utility class does not modify collection methods when it converts Arrays to lists. Such as add, clear and remove
  11. In JDK7 and above, the ComparatorThree conditions are met, otherwise callArrays. Sort () or Collections. Sort ()Exceptions will be reported.
    • The comparison of x and y is the opposite of the comparison of y and x
    • Transitivity: x>y and y>z, then x must be greater than z
    • Symmetry: x=y, the comparison result of X and z is the same as the comparison result of y and z
  12. Use entrySet to traverse the Map class set K/V instead of keySet
    • The keySet is iterated twice, once to an Iterator and once to fetch the value of the key from the hashMap, if JDK8 can use the map.foreach method
  13. Thread resources must be provided by the thread pool and the created thread cannot be displayed in the application itself. Do not use Executors to create a thread pool. Use ThreadPoolExecutor to clear the running rules of the thread pool and avoid resource depletion.
  14. SimpleDateFormat isThread-unsafe classesIn general, do not define a variable as static. If static, you must lock it or use the DateUtils utility class
    • For JDK8 applications, you can use Instant(for time statistics) instead of Date, LocalDateTime instead of Calendar, and DateTimeFormatter instead of SimpleDateFormat
  15. Avoid Random instances being used by multiple threads because sharing the instance, while thread-safe, can degrade performance by competing for the same seed
    • After JDK7, API ThreadLocalRandom can be used directly, whereas prior to JDK7, coding is required to ensure that each thread holds an instance.
  16. Classes, class attributes, and class methods must be annotated using the Javadoc specification, the use of/ * * * / contentFormat, must not be used//xxxway
  17. All abstract methods, including those in the interface, must be annotated in Javadoc, specifying what the method does and implements in addition to its return values, parameters, and exception descriptions. All classes must have a creator and creation date added.
  18. For code snippets that have been commented out temporarily and may be restored later, use three slashes above the commented code///To make a case for commenting code
  19. Ensure unit test independence. To ensure that unit tests are stable, reliable and easy to maintain, unit tests cannot call each other or depend on the order in which they are executed.
  20. For high-concurrency servers, reduce the TIME_await timeout of TCP and increase the maximum number of event handles (fd).

1.1 Points worth explaining

Do not allow any mana values (undefined constants) to appear directly in code

Example:


    Negative example:
    //Magic values, except for predefined, are forbidden in coding.
    if (key.equals("Follow the public account: Java3y")) {
        / /...
    }

    Positive example:
    String KEY_PRE = "Follow the public account: Java3y";
    if (KEY_PRE.equals(key)) {
        / /...
    }

Copy the code

Ps: I guess the constant is defined first, so it is convenient for reference/modification later.


(2) Object’s euqals method is prone to throw null pointer exceptions. Call equals using a constant or a valued Object. The java.util.Object#equals utility class is recommended

Source code for java.util.Object#equals (already checked null case)


	public static boolean equals(Object a, Object b) {
        return(a == b) || (a ! =null && a.equals(b));
    }
Copy the code

AsList () does not allow you to modify collection methods when you convert Arrays to lists.

Because the returned ArrayList is an inner class, it does not implement the collection’s modification methods. The data in the background is still an array, which represents the adapter pattern.


In JDK7 and above, the Comparator must satisfy reflexivity, transitivity, and symmetry, otherwise the call to arrays.sort () or collections.sort () will generate an exception.

The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

  • 1) The comparison of x and y is opposite to the comparison of y and x.
  • 2) Transitivity: x>y,y>z, then x>z.
  • 3) Symmetry: x=y, then the comparison result of X and z is the same as that of y and z.

Counterexample: In the following example, equality is not handled. Exceptions may occur in actual use:


new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getId() > o2.getId() ? 1 : -1; }}Copy the code

Use entrySet to traverse the Map class set K/V instead of keySet

First let’s look at how to traverse a HashMap using keySet:


    public static void main(String[] args) throws InterruptedException {

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("Concerned Public Account :"."Java3y");
        hashMap.put("Stick to the original"."Java3y");
        hashMap.put("Thumb up"."Follow, retweet, share.");


        // get the keySet, iterate through the keySet to get all the keys
        Set<String> strings = hashMap.keySet();
        Iterator<String> iterator = strings.iterator();
        while (iterator.hasNext()) {

            // Each key of the HashMap
            String key = iterator.next();

			// If you have seen HashMap, the time complexity of get method is O(1)
            System.out.println("key = " + key + ", value = "+ hashMap.get(key)); }}Copy the code

Take a look at the source code again:


// 1. Get the keySet, if it does not exist, create it
public Set<K> keySet(a) {
    Set<K> ks = keySet;
    if (ks == null) {
        ks = new KeySet();
        keySet = ks;
    }
    return ks;
}

// 2. Initialize ks (actually Set [inner class of HashMap], need to initialize iterator while initializing)
ks = new AbstractSet<K>() {
    public Iterator<K> iterator(a) {
        return new Iterator<K>() {
            private Iterator<Entry<K,V>> i = entrySet().iterator();

            public boolean hasNext(a) {
                return i.hasNext();
            }

            public K next(a) {
                return i.next().getKey();
            }

            public void remove(a) { i.remove(); }}; }};Copy the code

Let’s look at entrySet. You can get the key and the value directly instead of using the get method to get the value.


    public static void main(String[] args) throws InterruptedException {

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("Concerned Public Account :"."Java3y");
        hashMap.put("Stick to the original"."Java3y");
        hashMap.put("Thumb up"."Follow, retweet, share.");


        // Get entrySet
        Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            System.out.println("key = " + entry.getKey() + ", value = "+ entry.getValue()); }}Copy the code

For JDK8, it is recommended to use map.foreach () directly.


public static void main(String[] args) throws InterruptedException {

    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put("Concerned Public Account :"."Java3y");
    hashMap.put("Stick to the original"."Java3y");
    hashMap.put("Thumb up"."Follow, retweet, share.");

    
    / / forEach usage
    hashMap.forEach((key, value) -> System.out.println("key = " + key + ", value = " + value));
}

Copy the code

ForEach encapsulates entrySet and provides forEach for us to easily traverse the Map collection



	/ / forEach source code
    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw newConcurrentModificationException(ise); } action.accept(k, v); }}Copy the code

5. SimpleDateFormat is a thread-unsafe class and should not be defined as static. If it is static, you must lock it or use DateUtils.

There are examples where SimpleDateFormat can be used correctly:


// 1. There is no thread-safety problem when used inside a method
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";
public String getFormat(Date date){
    SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT);
    return dateFormat.format(date);
}


// 2. Lock every time you use it
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void getFormat(a){
    synchronized (SIMPLE_DATE_FORMAT){
    SIMPLE_DATE_FORMAT.format(newDate()); ... .; }// 3. With ThreadLocal, each thread has its own SimpleDateFormat object that does not interfere with each other
private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue(a) {
        return new SimpleDateFormat("yyyy-MM-dd"); }};// 4. Use DateTimeFormatter(This class is immutable and threadsafe.)

    DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    System.out.println(timeFormatter.format(LocalDateTime.now()));

Copy the code

For JDK8 applications, you can use Instant instead of Date, LocalDateTime instead of Calendar, and DateTimeFormatter instead of SimpleDateFormat.


Second, database related

  1. Fields expressing whether concepts must be named as isxxx and the data type is unsigned tinyint(1 for yes, 0 for no)
  2. Use decimal for decimal types, and prohibit float and double.
  3. Varchar is a variable string of up to 5000 characters without pre-allocated storage. If yes, use text to separate a table and use the primary key to avoid affecting the index efficiency of other fields.
  4. The table must have three columns: id(type unsigned bigint), gmT_CREATE (created time), gme_modified(modified time)
  5. Fields allow for some redundancy to improve query performance, but data consistency must be considered. Redundant fields must not be frequently modified fields or varhar long fields (and certainly not text fields).
  6. If the number of rows in a table exceeds 5 million or the size of a table exceeds 2GB, it is recommended to create a separate table.
  7. Do not use a join for more than three tables. The data types of the fields to be joined must be the same. When multiple tables are used for associated query, ensure that the associated fields have indexes.
  8. When creating an index on a VARCHAR field, you must specify the index length,There is no need to index the full field, page searchNo left blur or full blur, if necessary through the search engine to solve.
    • Make full use of the left-most prefix matching feature!
  9. Use delayed association or subquery to optimize super – multiple scenarios.
  10. If there is a need for globalization, all are encoded in UTF-8. To store emoticons, select UTF8MB4.

2.1 Points worth explaining

1. Use delayed association or sub-query to optimize super – multiple scenarios.

MySQL does not skip the offset line. Instead, it takes offset+N and returns N. When the offset is very large, it is very inefficient to either control the total number of pages returned, or perform SQL rewriting if the number of pages exceeds a certain threshold.

Example:

/ / before optimizationSELECT id, cu_id, name, info, biz_type
	, gmt_create, gmt_modified, start_time, end_time, market_type
	, back_leaf_category, item_status, picuture_url
FROM relation
WHERE biz_type = '0'
	AND end_time >= '2014-05-29'
ORDER BY id ASC
LIMIT 149420.20; / / after optimizationSELECT a.*
FROM relation a, (
		SELECT id
		FROM relation
		WHERE biz_type = '0'
			AND end_time >= '2014-05-29'
		ORDER BY id ASC
		LIMIT 149420.20
	) b
WHERE a.id = b.id

Copy the code

This is done by using the overwrite index query to return the required primary key, and then associating the original table with the primary key to obtain the required data. This makes full use of the index!


Unresolved problems

When reading the manual, there are still some knowledge points that I haven’t read or practiced, and there are many knowledge points involved. Please mark them here and come back to fill the holes when you meet them later or when you are free

  • CountDownLatch is used for asynchronous to synchronous operations. Each thread must call the countDown method before exiting. The thread executes code that watches for a catch exception and ensures that the countDown method is executed, so that the main thread cannot execute to the await method until it times out. Note: The child thread throws an exception stack that cannot be caught in the main try-catch thread.
  • Multiple reads on one write can solve variable synchronization problems, but multiple writes cannot solve thread safety problems. If the count++ operation is implemented using the following class:AtomicInteger count = new AtomicInteger(); count.addAndGet(1);If it is JDK8, the LongAdder object is recommended for better performance than AtomicLong (reducing the number of optimistic lock retries).
  • Use JDK8’s Optional class to prevent NPE problems.

Of course, if you have something good to read, let me know in the comments section. I will also mark stay and have a good look.

For example: “3y, I found a great article in the Optional category with the url XXXX (book name is XXX).


Since I don’t have a lot of experience now, I have to go back to the following chapters:

  • “Log Specification”, “Engineering Structure”, “Design Specification” in manual

The last

As you can see from what I’ve written above, in addition to a few specifications, there are a number of practical tips that we can use to help us develop. There were also some things I didn’t know much about at this stage (” journal “,” design “,” binary library “), which I had to revisit as I grew up.

  • Ps: I’ll be back to fix the hole.

To quote from the book:

Many programming methods are objectively neither right nor wrong. Consistency is important, readability is important, and team communication efficiency is important. Programmers naturally need to work as a team, and the positive energy of collaboration lies in communicating problems effectively. Personalization should be shown as far as possible in the improvement of system architecture and algorithm efficiency, rather than in the cooperation of the specification of the entangled discussion, debate, no final conclusion.

The author (Gu Ju) answered in Zhihu:

Reading does not mean remembering, remembering does not mean understanding, understanding does not mean being able to apply, the real knowledge is practice, practice, practice.

If you think my writing is good, know this:

  • Stick to the original technical public account: Java3y
  • The table of contents navigation of this article (exquisite brain map + massive video resources) : github.com/ZhongFuChen…