После прочтения "Руководства по разработке Java для Alibaba"

Java задняя часть Алибаба модульный тест

предисловие

Только лысина может стать сильнее

Я изучал Redis некоторое время назад, но меня оскорбили в золотом ранге, и я не могу подняться до этого ранга в настоящее время, и я не могу получать свою первую победу каждый день (так раздражает).

Воспользовавшись школьной спортивной встречей,РазумныйЯ дал себе небольшой длительный отпуск, а затем отправился домой. Придя домой, я обнаружил, что 618 купил кучу книг в то время, и книги были еще не распакованы.... Так что я вытащил тончайшую книгу "Alibaba Java Development Manual"

手册

В этой книге всего более 90 страниц, и ее можно прочитать за один день.прочитатьЗакончилось, я вернусь после прочтенияводаСообщение блога.

Уведомление:

  • Многих описанных в книге спецификаций можно избежать с помощью IDE, и многие из них были известны раньше.
  • Итак, эта статьятолько записьЯ думаю, что важнее, или какие-то спецификации (очки знаний), которые я не замечал при разработке раньше.
  • Содержание этой статьи определенно не такое полное, как в книге.Если вам интересно, вы можете купить копию и прочитать ее~

Официальный адрес PDF:

1. Связанный с Java

  1. POJO — это собирательное имя DO/DTO/BO/VO, и его запрещено называть xxxPOJO.
  2. Метод получения нескольких объектов имеет префикс list
  3. Статистические методы, используемые для получения значения счетчика в качестве префикса
  4. Не добавляйте префикс is к логическим переменным в классе POJO, иначе синтаксический анализ некоторых фреймворков вызовет ошибки сериализации.
    • Если ваша переменная имеет имя, такое как isActive, она может считаться активной при разборе фреймворка.
  5. Если это имя интерфейса, описывающее возможность, возьмите соответствующее прилагательное в качестве имени интерфейса (обычно в форме -able)
  6. Мана запрещена(Неопределенные константы) появляются непосредственно в коде
  7. Метод объекта euqals склонен генерировать исключения нулевого указателя. Вы должны вызывать equals с константой или объектом со значением. Рекомендуемое использованиеjava.util.Object#equalsИнструменты
  8. Все POJOсвойства классаиспользовать всетип данных оболочки, необходимо использовать возвращаемое значение и параметры RPCУпаковкатип данных, вселокальная переменнаяоба используютосновные данныетип. При определении классов POJO, таких как VO/DTO/DO, не устанавливайте значение по умолчанию для любого свойства.
    • Если ваше свойство класса использует примитивный тип данных, такой как int, значение по умолчанию равно 0. При нормальных обстоятельствах переменной не присваивается значение, и обычно вы хотите выразить, что она не существует (нуль), а не 0.
  9. В конструктор запрещено добавлять какую-либо бизнес-логику, если логику инициализации можно поместить в метод init. Не добавляйте бизнес-логику в методы установки/получения.
    • Если метод набора / получения введен в бизнес-логику, иногда он становится очень неприятным для устранения неполадок проблемы
  10. Когда служебный класс Arrays.asList() преобразует массив в список, он не может использовать соответствующие методы изменения коллекции. Например добавить, очистить, удалить
  11. В JDK7 и выше Comparator долженвыполнить три условия, иначе позвонитеArrays.sort()或者Collections.sort()Будет сообщено об исключении.
    • Результат сравнения x, y противоположен результату сравнения y, x
    • Транзитивность: x>y и y>z, тогда x должен быть больше z
    • Симметрия: x=y, тогда результат сравнения x, z такой же, как и у, z
  12. Используйте entrySet для обхода набора классов Map K/V вместо обхода с помощью keySet
    • KeySet проходится дважды, один раз для преобразования его в объект Iterator и один для извлечения значения, соответствующего ключу, из hashMap.Если JDK8 может использовать метод Map.foreach
  13. Ресурсы потока должныПредоставляется пулом потоков, не разрешается явно создавать потоки в самом приложении. Пул потоковСоздание с Executors запрещено, созданный ThreadPoolExecutor, этот способ обработки позволяет инженерам, пишущим код, лучше понимать правила выполнения пула потоков и избегать риска исчерпания ресурсов.
  14. SimpleDateFormatпоток небезопасный класс, как правило, не определяйте ее как статическую переменную, если она определена как статическая, ее необходимо заблокировать или использовать класс инструментов DateUtils.
    • Если приложение JDK8, вы можете использовать Instant (дляСтатистика времении т.д.) вместо Date, LocalDateTime вместо Calendar, DateTimeFormatter вместо SimpleDateFormat
  15. Избегайте использования экземпляра Random несколькими потоками. Хотя совместное использование экземпляра является потокобезопасным, это приведет к снижению производительности из-за конкуренции за одно и то же начальное число.
    • После JDK7 вы можетеИспользовать API ThreadLocalRandom напрямую, в то время как до JDK7 требовалось кодирование, чтобы каждый поток содержал экземпляр.
  16. Комментарии для классов, свойств класса и методов класса должны использовать спецификацию Javadoc.,использовать/**内容*/формат, не должен использовать//xxxСпособ
  17. всеабстрактный метод(В том числе методы в интерфейсах) должны быть аннотированы с помощью Javadoc. Помимо возвращаемых значений, параметров и описаний исключений, он также должен указывать, что делает метод и какие функции он реализует.Все курсы должны указывать создателя и дату создания.
  18. Для фрагментов кода, которые временно закомментированы и могут быть восстановлены позже, используйте три косые черты над закомментированным кодом.///чтобы оправдать комментирование кода
  19. Гарантировано модульное тестированиенезависимость. Чтобы убедиться, что модульные тесты стабильны, надежны и просты в обслуживании, между модульными тестамине могут звонить друг другу,такжене может полагаться на порядок исполнения.
  20. Для серверов с высокой степенью параллелизма рекомендуется уменьшить время ожидания time_await протокола TCP и увеличить максимальное количество дескрипторов событий (fd).

1.1 Моменты, которые стоит пояснить

1. Магическое значение не допускается (Неопределенные константы) появляются непосредственно в коде

пример:


    Negative example:
    //Magic values, except for predefined, are forbidden in coding.
    if (key.equals("关注公众号:Java3y")) {
        //...
    }

    Positive example:
    String KEY_PRE = "关注公众号:Java3y";
    if (KEY_PRE.equals(key)) {
        //...
    }

ps: я думаю, очень удобно сначала определить константы, а затем ссылаться/изменять их позже.


два,Метод euqals объекта склонен генерировать исключения нулевого указателя, вы должны использовать константы или объекты со значениями для вызова equals. Рекомендуемое использованиеjava.util.Object#equalsИнструменты

Исходный код java.util.Object#equals (был рассмотрен случай null)


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

3. Когда класс инструмента Arrays.asList() преобразует массив в список, он не может использовать соответствующие методы модификации коллекции.

потому что возвращенный ArrayList являетсявнутренний класси не реализует метод модификации коллекции.Данные в фоновом режиме по-прежнему являются массивом, вот шаблон адаптера.

ArrayList在这里是内部类


4. В JDK7 и выше Comparator долженУдовлетворить рефлексивность, транзитивность, симметрию, иначе позвонитеArrays.sort()或者Collections.sort()Будет сообщено об исключении.

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) Результат сравнения x, y противоположен результату сравнения y, x.
  • 2) Транзитивность: x>y, y>z, затем x>z.
  • 3) Симметрия: x=y, тогда результат сравнения x, z такой же, как и у, z.

Пример счетчика: в следующем примерене обрабатывает равенство, при фактическом использовании могут возникать исключения:


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

Используйте entrySet для обхода набора классов Map K/V вместо обхода с помощью keySet

Во-первых, давайте посмотрим, как пройти по HashMap с помощью keySet:


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

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("关注公众号:", "Java3y");
        hashMap.put("坚持原创", "Java3y");
        hashMap.put("点赞", "关注,转发,分享");


        // 得到keySet,遍历keySet得到所有的key
        Set<String> strings = hashMap.keySet();
        Iterator<String> iterator = strings.iterator();
        while (iterator.hasNext()) {

            // HashMap的每个key
            String key = iterator.next();

			// 通过key可以获得对应的value,如果有看过HashMap的同学知道get方法的时间复杂度是O(1)
            System.out.println("key = " + key + ", value = " + hashMap.get(key));
        }

    }



Давайте еще раз посмотрим на исходный код:


// 1. 得到keySet,如果不存在,则创建
public Set<K> keySet() {
    Set<K> ks = keySet;
    if (ks == null) {
        ks = new KeySet();
        keySet = ks;
    }
    return ks;
}

// 2.初始化ks (实际上就是Set集合[HashMap的内部类],在初始化时需要顺便初始化iterator)
ks = new AbstractSet<K>() {
    public Iterator<K> iterator() {
        return new Iterator<K>() {
            private Iterator<Entry<K,V>> i = entrySet().iterator();

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

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

            public void remove() {
                i.remove();
            }
        };
    }

};




Давайте еще раз взглянем на entrySet,Вы можете получить ключ и значение напрямую, не используя метод get для получения значения, поэтому это более рекомендуется, чем keySet!


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

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("关注公众号:", "Java3y");
        hashMap.put("坚持原创", "Java3y");
        hashMap.put("点赞", "关注,转发,分享");


        // 得到entrySet,遍历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());
        }
    }

Если это JDK8, рекомендуется использовать его напрямуюMap.forEach()Что ж, давайте посмотрим на использование:


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

    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put("关注公众号:", "Java3y");
    hashMap.put("坚持原创", "Java3y");
    hashMap.put("点赞", "关注,转发,分享");

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

На самом деле, мы можем найти в исходном коде, что forEach на самом деле инкапсулирует entrySet, предоставляя нам forEach.Более удобноперебрать коллекцию Map



	// forEach源码
    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 new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

5. SimpleDateFormatпоток небезопасный класс, как правило, не определяйте ее как статическую переменную, если она определена как статическая, ее необходимо заблокировать или использовать класс инструментов DateUtils.

Вот следующие примеры правильного использования SimpleDateFormat:


// 1. 在方法内部使用,没有线程安全问题
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. 每次使用的时候加锁      
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void getFormat(){
    synchronized (SIMPLE_DATE_FORMAT){
    SIMPLE_DATE_FORMAT.format(new Date());
    ….;
}
        
// 3. 使用ThreadLocal,每个线程都有自己的SimpleDateFormat对象,互不干扰
private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};

// 4. 使用DateTimeFormatter(This class is immutable and thread-safe.)

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

Если это приложение JDK8, вы можете использовать Instant вместо Date, LocalDateTime вместо Calendar и DateTimeFormatter вместо SimpleDateFormat.


2. Связанные с базой данных

  1. Поле, которое указывает, должно ли использоваться понятиеisxxx имя пути, тип данныхunsigned tinyint(1 означает да, 0 означает нет)
  2. Для десятичного типаdecimal, использование float и double запрещено.
  3. varchar — это переменная строка символов, длина которой не должна превышать 5000 символов без предварительного выбора для выделения места для хранения. Если он превышает, используйте текст, отдельную таблицу и используйте первичный ключ для соответствия, чтобы не влиять на другие поля.эффективность индексации.
  4. Три необходимые поля для таблицы: ID (тип без знака без знака), gmt_create (время создания), gme_modified (время модификации)
  5. Поля допускают соответствующую избыточность для повышения производительности запросов, но необходимо учитывать согласованность данных. Лишние поля должныЭто не поле, которое часто модифицируется, не сверхдлинное поле varhar (не текстовое поле).
  6. Количество строк в одной таблицеБолее 5 миллионов строк или одна таблица объемом более 2 ГБрекомендуемыеПодбиблиотека и подтаблица(Если не ожидается, что этот объем данных будет достигнут через три года, не разделяйте базу данных и не разделяйте таблицу при создании таблицы!)
  7. Более трех таблиц запрещают использование соединения, типы данных полей, которые необходимо объединить, должны быть согласованными.Когда с запросом связано несколько таблиц, гарантируетсяСвязанное поле должно иметь индекс!
  8. При индексировании поля varchar необходимо указать длину индекса,Нет необходимости индексировать все поля, поиск по страницеРазмытие слева или полное размытие строго запрещено., и разрешить его через поисковую систему, если это необходимо.
    • Воспользуйтесь функцией сопоставления крайнего левого префикса!
  9. использоватьотсроченная ассоциацияИли слишком много оптимизаций подзапросов тоже разбиты на сценарии.
  10. Если есть необходимость в глобализации, они кодируются в utf-8. Если вам нужно хранить выражения, выберите для хранения utf8mb4.

2.1 Моменты, которые стоит пояснить

1. Используйтеотсроченная ассоциацияИли слишком много оптимизаций подзапросов тоже разбиты на сценарии.

MySQL не пропускает строку смещения, а берет строку смещения + N, затем возвращает строку смещения, прежде чем сдаться, и возвращает строку N, затем, когда смещение особенно велико, эффективность очень низкая, либо контролируйте общее количество возвращенных страниц или перезаписи SQL для количества страниц, превышающего определенный порог.

пример:


// 优化前

SELECT 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;


// 优化后

SELECT 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

Объяснение: На самом деле, здесь используетсяЗапрос покрывающего индекса возвращает желаемый первичный ключ, а затем согласноПервичный ключ связывается с исходной таблицей для получения необходимых данных.. Вот и всеполное использование индексов!


3. Нерешенные вопросы

При чтении «Руководства» все еще есть некоторые моменты знаний, которые не были прочитаны или отработаны, и включают много пунктов знаний.markВернитесь и восполните яму, когда вы столкнетесь с ней позже или когда у вас будет время~

  • Используйте CountDownLatch для асинхронной и синхронной операции. Метод countDown должен вызываться перед выходом каждого потока. Код выполнения потока обращает внимание на перехват исключений, чтобы гарантировать, что метод countDown выполняется, чтобы основной поток не смог выполнить метод ожидания. , Результат не будет возвращен до тайм-аута. Примечания: обратите внимание, что дочерний поток выдает стек исключений, который невозможно перехватить в основном потоке.
  • При одной записи и большом количестве чтений проблема синхронизации переменных может быть решена, но при большем количестве операций записи это также не может решить проблему потокобезопасности. Если это операция count++, используйте для реализации следующий класс:AtomicInteger count = new AtomicInteger(); count.addAndGet(1);Если это JDK8, рекомендуется использовать объект LongAdder, который имеет лучшую производительность, чем AtomicLong (уменьшает количество оптимистичных попыток блокировки).
  • Используйте дополнительный класс JDK8, чтобы предотвратить проблемы NPE.

Конечно, если у вас есть лучшая информация, вы также можете сказать мне в области комментариев. Я также буду жить в Марке.

Например: «3y, я обнаружил, что в классе Optional есть очень хорошая статья, URL — xxxx (название книги — xxx)


Поскольку определенного опыта сейчас не накоплено, необходимо пересмотреть следующие главы:

  • «Спецификация журнала», «Техническая структура», «Техническая спецификация» в Руководстве.

Наконец

Как видите из того, что я написал выше, помимо некоторых спецификаций, существует множествопрактичныйЭти советы полезны для нашего развития. На данном этапе у меня также есть некоторые вещи, которые я особо не трогал ("лог", "дизайн", "сторонняя библиотека"), все это требует от меняПросто продолжайте оглядываться назад, когда вы растете.

  • ps: я вернусь, чтобы сделать яму.

Цитата из книги:

Во многих методах программирования нет правильного или неправильного.Важна согласованность, важна удобочитаемость и важна эффективность командной коммуникации. Программистам, естественно, нужна командная работа, и позитивная энергия сотрудничества должна быть направлена ​​на эффективное обсуждение проблем. Персонализация должна проявляться в максимально возможном улучшении архитектуры системы и эффективности алгоритмов, а не в бесконечных дискуссиях и спорах о нормах сотрудничества, а выводов в итоге нет.

Автор (одинокий) ответил на предложение на Чжиху:

Законченное чтение не означает запоминание, запоминание не означает понимание, понимание не означает, что его можно применять, настоящее знание — это практика, практика, практика..

Если вы думаете, что я написал хорошо, проверьте:

  • настаиватьоригинальныйТехнический общедоступный номер: Java3y
  • статьиНавигация по каталогу(Изысканная карта мозга + огромные видеоресурсы):GitHub.com/Zhongf UC очень…