>  기사  >  Java  >  Java 코딩 사양 분석

Java 코딩 사양 분석

怪我咯
怪我咯원래의
2017-06-25 10:12:352279검색

1. 프로그래밍 규칙

(1) 명명 규칙

1. [필수] 코드의 이름은 밑줄이나 달러 기호로 시작할 수 없으며 밑줄이나 달러 기호로 끝날 수도 없습니다.

 카운터 예시 : _nam / __name / $Object / name_ / name$ / Object$
2. [필수] 코드 내 네이밍에 병음과 영어를 혼합하여 사용하는 것은 엄격히 금지되며, 사용도 금지됩니다. 직접 중국어.

 참고: 올바른 영어 철자와 문법을 사용하면 독자가 쉽게 이해하고 모호함을 피할 수 있습니다. 순수한 병음 이름도 피해야 합니다.

  카운터 예시: DaZhePromotion [Discount] / getPingfenByName() [Rating] / int 특정 변수 = 3

  긍정적 예시: alibaba / taobao / youku / hangzhou 및 기타 국제 이름은 영어와 동일하다고 간주할 수 있습니다.
3. [필수] 클래스 이름은 UpperCamelCase 스타일을 사용해야 하며 다음을 제외하고는 Camel Case를 따라야 합니다. (도메인 모델 관련 명명) DO / BO / DTO / VO 등

  긍정적인 예: MarcoPolo / UserDO / CamelCase를 따라야 합니다.

  긍정적인 예: localValue / getHttpMessage() / inputUserId
5. [필수] 상수 이름은 모두 대문자이어야 하며 단어는 밑줄로 구분되어야 합니다. 완전하고 명확한 의미를 표현하도록 노력하고 긴 이름을 싫어하지 않습니다.

  긍정적인 예: MAX_STOCK_COUNT

  카운터 예: MAX_COUNT

6. [필수] 추상 클래스 이름은 Abstract 또는 Base로 시작하고, 예외 클래스 이름은 Exception으로 끝납니다. 테스트하고 테스트로 끝납니다.

7. [필수] 대괄호는 배열 유형의 일부입니다. 배열은 다음과 같이 정의됩니다. String[] args;


Counter 예: 정의하는 데 String args[]를 사용하지 마세요.
8. [필수] POJO 클래스의 부울 유형 변수에 is를 추가하지 마십시오. 그렇지 않으면 일부 프레임워크 구문 분석으로 인해 직렬화 오류가 발생합니다.

카운터 예: 기본 데이터 유형 boolean isSuccess로 정의된 속성은 isSuccess()입니다. RPC 프레임워크가 역방향 구문 분석을 수행하면 해당 속성 이름이 성공이라고 "생각"하여 속성이 실패하게 됩니다. 얻은 후 Exception이 발생했습니다.
9. [필수] 패키지 이름은 소문자를 사용해야 하며, 점 구분 기호 사이에는 자연스러운 의미를 지닌 영어 단어가 하나만 있어야 합니다. 패키지 이름은 항상 단수형을 사용하지만, 클래스 이름이 복수형의 의미를 갖는 경우 클래스 이름은 복수형을 사용할 수 있습니다.

  긍정적인 예: 애플리케이션 도구 클래스 패키지 이름은 com.alibaba.open.util이고, 클래스 이름은 MessageUtils입니다(이 규칙은 Spring 프레임워크 구조를 참조함)
10. 텍스트의 의미를 혼동합니다.

카운터 예: AbstractClass의 "약어"는 AbsClass로 명명되고, 조건의 "약어"는 condi로 명명됩니다.
11. [권장사항] 디자인 패턴을 사용하는 경우 클래스 이름에 특정 패턴을 반영하는 것이 좋습니다.

 참고: 이름에 디자인 패턴을 반영하면 독자가 건축 디자인 아이디어를 빠르게 이해하는 데 도움이 됩니다.

 긍정적인 예: public class OrderFactory;

  public class LoginProxy;

  public class ResourceObserver;

12. [권장] 인터페이스 클래스의 메서드와 속성에 수정자를 추가하지 마세요(공용도 추가하지 마세요). 코드의 간단한 속성을 유지하고 유효한 Javadoc 주석을 추가하세요. 인터페이스에서 변수를 정의하지 마십시오. 변수를 정의해야 하는 경우 해당 변수는 인터페이스 메소드와 관련되어야 하며 전체 애플리케이션의 기본 상수입니다.

  긍정적인 예: 인터페이스 메서드 서명: void f(); 인터페이스 기본 상수 표현: String COMPANY = "alibaba";

  반대 예: 인터페이스 메서드 정의: public abstract void f() 참고: JDK8의 인터페이스는 기본 구현을 허용합니다. 이면 이 기본 메소드는 모든 구현 클래스에 유용한 기본 구현입니다.

13. 인터페이스 및 구현 클래스의 이름 지정에는 두 가지 규칙이 있습니다.

 1) [필수] SOA 개념에 따라 서비스 및 DAO 클래스의 경우 노출되는 서비스는 인터페이스여야 하며 내부 구현 클래스는 Impl 접미사와 인터페이스의 차이점.

  긍정적인 예: CacheServiceImpl은 CacheService 인터페이스를 구현합니다.

  2) [권장사항] 기능을 설명하는 인터페이스 이름인 경우 해당 형용사를 인터페이스 이름으로 사용합니다(보통 –able 형식).

  긍정적인 예: AbstractTranslator는 Translatable을 구현합니다.

14. [참고] 열거형 클래스 이름에는 접미사 Enum을 추가하는 것이 좋습니다. 열거형 멤버의 이름은 모두 대문자여야 하며, 단어는 밑줄로 구분되어야 합니다.

 참고: 열거형은 실제로 특수 상수 클래스이며 생성자는 기본적으로 비공개로 설정됩니다.

  긍정적인 예: 열거 이름: DealStatusEnum, 멤버 이름: SUCCESS / UNKOWN_REASON.

15. [참고] 각 레이어의 명명 규칙:

  A) Service/DAO 레이어 메소드 명명 규칙

  1) 단일 객체를 얻는 방법 앞에는 get이 붙습니다.

  2) 여러 객체를 얻는 방법에는 목록이라는 접두어가 붙습니다.

  3) 통계값을 구하는 방법 앞에는 count가 붙는다.

  4) 삽입 방법 앞에는 저장(권장) 또는 삽입이 붙습니다.

  5) 삭제 방법 앞에는 제거(권장) 또는 삭제가 붙습니다.

  6) 수정 방법 앞에는 업데이트가 붙습니다.

 B) 도메인 모델 명명 규칙

  1) 데이터 객체: xxxDO, xxx는 데이터 테이블의 이름입니다.

  2) 데이터 전송 대상 : xxxDTO, xxx는 해당 사업 분야와 관련된 이름입니다.

  3) 표시 개체: xxxVO, xxx는 일반적으로 웹 페이지의 이름입니다.

  4) POJO는 DO/DTO/BO/VO의 총칭이며, xxxPOJO로 명명하는 것은 금지되어 있습니다.

(2) 상수 정의

1. [필수] 매직 값(즉, 정의되지 않은 상수)은 코드에 직접 나타날 수 없습니다.

 카운터 예시: String key="Id#taobao_"+tradeId;

   캐시.put(key, value);
2. [필수] long 또는 Long에 처음 값을 할당할 때 대문자 L을 사용해야 합니다. 소문자 l , 소문자는 숫자 1과 쉽게 혼동되어 오해를 불러일으킵니다.

 설명: Long a = 2l; 숫자 21로 작성합니까, 아니면 Long 유형 2로 작성합니까?
3. [권장사항] 모든 상수를 유지하려면 하나의 상수 클래스를 사용하지 마십시오. 갈라져. 예를 들어, 캐시 관련 상수는 클래스: CacheConsts 아래에 배치되고, 시스템 구성 관련 상수는 클래스: ConfigConsts 아래에 배치됩니다.

 참고: 크고 포괄적인 상수 클래스의 경우 검색 기능을 사용하여 수정된 상수를 찾아야 하며 이는 이해 및 유지 관리에 도움이 되지 않습니다.
4. [권장] 상수 재사용에는 애플리케이션 간 공유 상수, 애플리케이션 내 공유 상수, 하위 프로젝트 내 공유 상수, 패키지 내 공유 상수, 클래스 내 공유 상수의 5가지 수준이 있습니다.

 1) 애플리케이션 간 공유 상수: 일반적으로 client.jar의 상수 디렉터리에 있는 타사 라이브러리에 배치됩니다.

 2) 애플리케이션 내 공유 상수: 라이브러리 모듈의 상수 디렉터리에 위치합니다.

 카운터 예시: 이해하기 쉬운 변수도 애플리케이션 내에서 공유 상수로 균일하게 정의되어야 합니다. 두 공성 마스터는 두 클래스에서 "예"를 나타내는 변수를 정의했습니다.

  클래스 A: public static final String YES = " yes";

   클래스 B: public static final String YES = "y"; A.YES.equals(B.YES), 예상 값은 true이지만 실제 반환은 false이므로 온라인 문제가 발생합니다.
 3) 하위 프로젝트 내 공유 상수, 즉 현재 하위 프로젝트의 상수 디렉터리에 있습니다.

 4) 패키지 내 공유 상수, 즉 현재 패키지 아래의 별도 상수 디렉터리에 있습니다.

 5) 클래스 내 공유 상수: 클래스 내부에서 직접 비공개 정적 최종 정의.
5. [권장] 변수 값이 범위 내에서만 변경되는 경우 Enum 클래스를 사용하세요. 이름 이외의 확장 속성이 있는 경우 Enum 클래스를 사용해야 합니다. 다음 예제의 숫자는 요일을 나타내는 확장 정보입니다.

  긍정적인 예: public Enum{ MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);}

(3) 형식 협약

1. [필수] 교정기 사용에 관한 협약입니다. 중괄호가 비어 있으면 줄 바꿈 없이 간단히 {}를 작성하세요. 비어 있지 않은 코드 블록인 경우:

 1) 왼쪽 중괄호 앞에 줄 바꿈이 없습니다.

 2) 왼쪽 중괄호 뒤에 줄 바꿈이 있습니다.

 3) 오른쪽 중괄호 앞에 줄 바꿈이 있습니다.

 4) 오른쪽 중괄호 뒤에 else 코드가 있으면 줄 바꿈이 없습니다. 이는 오른쪽 중괄호를 종료한 후 줄을 끊어야 함을 의미합니다.
2. [필수] 왼쪽 괄호와 다음 문자 사이에는 공백이 없습니다. 마찬가지로 오른쪽 괄호와 이전 문자 사이에도 공백이 없습니다. 자세한 내용은 기사 5 아래의 올바른 예시 팁을 참조하세요.
3. [필수] if/for/while/switch/do 등 예약어와 좌우 대괄호 사이에는 공백을 추가해야 합니다.
4. [필수] 모든 운영자 주변에는 공간이 있어야 합니다.

 설명: 연산자에는 할당 연산자 =, 논리 연산자 &&, 덧셈, 뺄셈, 곱셈 및 나눗셈 기호, 삼항 연산자 등이 포함됩니다.
5. [필수] 들여쓰기는 공백 4개를 사용하며, 탭 문자는 금지됩니다.
참고: 탭 들여쓰기를 사용하는 경우 들여쓰기를 설정해야 합니다. 들여쓰기를 설정해야 합니다. 들여쓰기를 설정해야 합니다. 들여쓰기를 설정해야 합니다. 들여쓰기를 설정해야 합니다. 탭 1개를 공백 4개로 설정해야 합니다. IDEA가 탭을 4개의 공백으로 설정하는 경우 Eclipse에서 탭 문자 사용을 선택하지 말고 탭에 대한 공백 삽입을 확인해야 합니다.
긍정적인 예: (1-5점 포함)

public static void main(String args[]) {// 缩进4个空格String say = "hello";// 运算符的左右必须有一个空格int flag = 0;// 关键词if与括号之间必须有一个空格,括号内的f与左括号,0与右括号不需要空格if (flag == 0) {
            System.out.println(say);
        }// 左大括号前加空格且不换行;左大括号后换行if (flag == 1) {
            System.out.println("world");// 右大括号前换行,右大括号后有else,不用换行} else {
            System.out.println("ok");// 在右大括号后直接结束,则必须换行        }
    }

6. 【强制】单行字符数限不超过 120 个,超出需要换行时 个,超出需要换行时 遵循如下原则:

  1) 第二行相对一缩进 4个空格,从第三行开始不再继续缩进参考示例。

  2) 运算符与下文一起换行。

  3) 方法调用的点符号与下文一起换行。

  4) 在多个参数超长,逗号后进行换行。

  5) 在括号前不要换行,见反例。

  正例:
    StringBuffer sb = new StringBuffer();
    //超过120个字符的情况下,换行缩进4个空格,并且方法前的点符号一起换行
    sb.append("zi").append("xin")...
    .append("huang")...
    .append("huang")...
    .append("huang");
  反例:
    StringBuffer sb = new StringBuffer();
    //超过120个字符的情况下,不要在括号前换行
    sb.append("zi").append("xin")...append
    ("huang");
    //参数很多的方法调用可能超过120个字符,不要在逗号前换行
    method(args1, args2, args3, ...
    , argsX);
7. 【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。

  正例:下例中实参的"a",后边必须要有一个空格。
    method("a", "b", "c");
8. 【强制】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用windows格式。
9. 【推荐】没有必要增加若干空格来使某一行的字符与上一行的相应字符对齐。

  正例:

int a = 3;long b = 4L;float c = 5F;
StringBuffer sb = new StringBuffer();


참고: sb 변수를 추가하세요. 정렬이 필요한 경우 a, b, c에 공백을 몇 개 추가해야 합니다. 변수가 많을 때는 번거롭습니다.
10. [권장] 메소드 본문에서 실행문 그룹, 변수 정의문 그룹, 다른 비즈니스 로직 또는 다른 의미론 사이에 빈 줄을 삽입하세요. 동일한 비즈니스 로직과 의미 체계 사이에 빈 줄을 삽입할 필요가 없습니다.

 참고: 구분하기 위해 공백을 여러 줄 삽입할 필요는 없습니다.

(4) OOP 사양

1. [필수] 클래스의 객체 참조를 통해 이 클래스의 정적 변수 또는 정적 메서드에 액세스하지 마십시오. 그러면 컴파일러 구문 분석 비용이 불필요하게 증가합니다. 클래스 이름으로 직접 액세스하면 됩니다.
2. [필수] 모든 재정의 메서드에는 @Override 주석을 달아야 합니다.

 카운터 예: getObject() 및 get0object()에 문제가 있습니다. 하나는 문자 O이고 다른 하나는 숫자 0입니다. @Override를 추가하면 재정의 성공 여부를 정확하게 확인할 수 있습니다. 또한 추상 클래스에서 메서드 시그니처가 수정되면 해당 구현 클래스가 즉시 컴파일되고 오류를 보고합니다.
3. [필수] Java 변수 매개변수는 매개변수 유형과 비즈니스 의미가 동일한 경우에만 사용할 수 있습니다.

 참고: 변수 매개변수는 매개변수 목록의 끝에 배치되어야 합니다. (학생들은 가변 매개변수 프로그래밍을 최대한 피하는 것이 좋습니다)

  긍정적인 예: public User getUsers(String type, Integer... ids)
4 [필수] 원칙적으로 인터페이스의 메소드 시그니처는 외부는 인터페이스 호출자에게 영향을 미치지 않도록 수정될 수 없습니다. 인터페이스가 더 이상 사용되지 않는 경우 @Deprecated 주석을 추가해야 하며 새 인터페이스 또는 새 서비스를 명확하게 명시해야 합니다.
5. [필수] 오래된 클래스나 메소드는 사용할 수 없습니다.

 참고: java.net.URLDecoder의 decode(String encodeStr) 메소드는 더 이상 사용되지 않습니다. 두 매개변수 decode(String source, String encode)를 사용해야 합니다. 인터페이스 공급자는 분명히 오래된 인터페이스이므로 호출자로서 동시에 새로운 인터페이스를 제공해야 하며 오래된 메서드의 새로운 구현을 확인해야 합니다.
6. [필수] Object의 equals 메소드는 널 포인터 예외를 발생시키기 쉽습니다. 상수를 사용하거나 특정 값을 갖는 객체를 사용해야 합니다.

  긍정적인 예: "test".equals(object); 반대 예: object.equals("test");

  참고: java.util.Objects#equals(JDK7에서 도입된 도구 클래스)를 사용하는 것이 좋습니다
7 [필수] 동일한 유형의 패키징 클래스 객체 간의 모든 값 비교에는 equals 메서드를 사용합니다.

 참고: -128에서 127 사이의 Integer var=? 할당의 경우 IntegerCache.cache에서 Integer 개체가 생성되고 이 범위의 정수 값은 ==를 사용하여 직접 판단할 수 있습니다. 이 범위를 벗어나면 힙에 생성되며 기존 객체는 재사용되지 않습니다. 이는 판단을 위해 동등 방법을 사용하는 것이 좋습니다.
8. [필수] 기본 데이터 유형과 패키지 데이터 유형의 사용 기준은 다음과 같습니다.

 1) 모든 POJO 클래스 속성은 패키지 데이터 유형을 사용해야 합니다.

 2) RPC 메서드의 반환 값과 매개 변수는 래핑된 데이터 형식을 사용해야 합니다.

 3) 모든 로컬 변수[권장]는 기본 데이터 유형을 사용합니다.

 참고: POJO 클래스 속성에는 사용자가 이를 사용해야 할 때 명시적으로 값을 할당해야 함을 사용자에게 상기시키는 초기 값이 없습니다. 긍정적인 예: 자동 언박싱 및 기본 데이터 유형 수신에는 NPE 위험이 있으므로 데이터베이스의 쿼리 결과가 null일 수 있습니다.

 카운터 예시: 예를 들어 총 거래량의 상승과 하락, 즉 플러스 또는 마이너스 x%를 표시하며, x는 기본 데이터 유형이며, 호출된 RPC 서비스는 호출 실패 시 기본값을 반환합니다. , 페이지에 0%가 표시됩니다. 이는 불합리하며 대시로 표시되어야 합니다. 따라서 래핑된 데이터 유형의 null 값은 원격 호출 실패 및 비정상적인 종료와 같은 추가 정보를 나타낼 수 있습니다.
9. [필수] DO/DTO/VO 등 POJO 클래스를 정의할 때 속성 기본값을 설정하지 마세요.

카운터 예: POJO 클래스의 gmtCreate 기본값은 new Date()입니다. 그러나 이 속성은 데이터를 추출할 때 특정 값을 갖지 않습니다. 이 필드는 다른 필드가 업데이트될 때에도 업데이트되므로 생성 시간이 현재 시간으로 수정됩니다.
10. [필수] 직렬화 클래스에 새 속성을 추가할 때 직렬화 해제 실패를 방지하려면 serialVersionUID 필드를 수정하지 마세요. 업그레이드와 완전히 호환되지 않고 역직렬화 혼란을 피하려면 serialVersionUID 값을 수정하세요.

 참고: 일관되지 않은 serialVersionUID는 직렬화 런타임 예외를 발생시킵니다.
11. [필수] 초기화 로직이 있는 경우에는 생성 메소드에 비즈니스 로직을 추가하는 것이 금지됩니다.
12. [필수] POJO 클래스는 toString 메소드를 작성해야 합니다. IDE 도구 사용 시: source>generate toString, 다른 POJO 클래스를 상속하는 경우 앞에 super.toString을 추가해야 합니다.

  说明:在方法执行抛出异常时,可以直接调用POJO的toString()方法打印其属性值,便于排查问题。
13. 【推荐】使用索引访问用String的split方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛IndexOutOfBoundsException的风险。
  说明:
    String str = "a,b,c,,";
    String[] ary = str.split(",");
    //预期大于3,结果是3
    System.out.println(ary.length);
14. 【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读。
15. 【推荐】 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。 说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为方法信息价值较低,所有Service和DAO的getter/setter方法放在类体最后。
16. 【推荐】setter方法中,参数名称与类成员变量名称一致,this.成员名=参数名。在getter/setter方法中,尽量不要增加业务逻辑,增加排查问题的难度。

  反例:

public Integer getData() {if (true) {return data + 100;
        } else {return data - 100;
        }
    }

17. 【推荐】循环体内,字符串的联接方式,使用StringBuilder的append方法进行扩展。 反例:

String str = "start";for (int i = 0; i < 100; i++) {
    str = str + "hello";
}

说明:反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,造成内存资源浪费。
18. 【推荐】final可提高程序响应效率,声明成final的情况:

  1) 不需要重新赋值的变量,包括类属性、局部变量。

  2) 对象参数前加final,表示不允许修改引用的指向。

  3) 类方法确定不允许被重写。
19. 【推荐】慎用Object的clone方法来拷贝对象。

  说明:对象的clone方法默认是浅拷贝,若想实现深拷贝需要重写clone方法实现属性对象的拷贝。
20. 【推荐】类成员与方法访问控制从严:

  1) 如果不允许外部直接通过new来创建对象,那么构造方法必须是private。

  2) 工具类不允许有public或default构造方法。

  3) 类非static成员变量并且与子类共享,必须是protected。

  4) 类非static成员变量并且仅在本类使用,必须是private。

  5) 类static成员变量如果仅在本类使用,必须是private。

  6) 若是static成员变量,必须考虑是否为final。

  7) 类成员方法只供类内部调用,必须是private。

  8) 类成员方法只对继承类公开,那么限制为protected。

  说明:任何类、方法、参数、变量,严控访问范围。过宽泛的访问范围,不利于模块解耦。

  思考:如果是一个private的方法,想删除就删除,可是一个public的Service方法,或者一个public的成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作用域太大,如果无限制的到处跑,那么你会担心的。

(五) 集合处理

1. 【强制】关于hashCode和equals的处理,遵循如下规则:

  1) 只要重写equals,就必须重写hashCode。

  2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。

  3) 如果自定义对象做为Map的键,那么必须重写hashCode和equals。

    正例:String重写了hashCode和equals方法,所以我们可以非常愉快地使用String对象作为key来使用。
2. 【强制】 ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;

  说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。
3. 【强制】 在subList场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均产生ConcurrentModificationException 异常。
4. 【强制】使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()。

  反例:直接使用toArray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误。

  正例:

List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);

说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。

5. 【强制】使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。

  说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。 String[] str = new String[] { "a", "b" }; List list = Arrays.asList(str);

  第一种情况:list.add("c"); 运行时异常。

  第二种情况:str[0]= "gujin"; 那么list.get(0)也会随之修改。
6. 【强制】泛型通配符来接收返回的数据,此写法的泛型集合不能使用add方法。

  说明:苹果装箱后返回一个对象,此对象就不能往里加任何水果,包括苹果。
7. 【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

  反例:

List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");for (String temp : a) {if ("1".equals(temp)) {
        a.remove(temp);
    }
}

说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的结果吗? 正例:

Iterator<String> it = a.iterator();while (it.hasNext()) {
    String temp = it.next();if (删除元素的条件) {
        it.remove();
    }
}

8. 【强制】 在JDK7版本以上,Comparator要满足自反性,传递性,对称性,不然Arrays.sort,Collections.sort会报IllegalArgumentException异常。

  说明:

  1) 自反性:x,y的比较结果和y,x的比较结果相反。

  2) 传递性:x>y,y>z,则x>z。

  3) 对称性:x=y,则x,z比较结果和y,z比较结果相同。

  反例:下例中没有处理相等的情况,实际使用中可能会出现异常:

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

9. 【推荐】集合初始化时,尽量指定集合初始值大小。 说明:ArrayList尽量使用ArrayList(int initialCapacity) 初始化。

10. 【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。

  说明:keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.foreach方法。

  正例:values()返回的是V值集合,是一个list集合对象;keySet()返回的是K值集合,是一个Set集合对象;entrySet()返回的是K-V值组合集合。
11. 【推荐】高度注意Map类集合K/V能不能存储null值的情况,如下表格:

集合类 Key Value Super 说明
Hashtable 不允许为null 不允许为null Dictionary 线程安全
ConcurrentHashMap 不允许为null 不允许为null AbstractMap 分段锁技术
TreeMap 不允许为null 允许为null AbstractMap 线程不安全
HashMap 允许为null 允许为null AbstractMap 线程不安全

 

 

 

 

  反例: 由于HashMap的干扰,很多人认为ConcurrentHashMap是可以置入null值,注意存储null值时会抛出NPE异常。
12. 【参考】合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。

  说明:稳定性指集合每次遍历的元素次序是一定的。有序性是指遍历的结果是按某种比较规则依次排列的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。
13. 【参考】利用Set元素唯一的特性,可以快速对一个集合进行去重操作,避免使用List的contains方法进行遍历、对比、去重操作。

(六) 并发处理

1. 【强制】获取单例对象需要保证线程安全,其中的方法也要保证线程安全。

  说明:资源驱动类、工具类、单例工厂类都需要注意。
2. 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

  正例:

public class TimerTaskThread extends Thread {public TimerTaskThread(){super.setName("TimerTaskThread"); 
    ...
}

3. 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。

  说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。

4. 【强制】线程池不允许使用 Executors去创建,而是通过ThreadPoolExecutor去创建,这样的处理方式让写同学更加明确线程池运行规则,避资源耗尽风险。

  说明: Executors返回的线程池对象的弊端如下 :

  1)FixedThreadPool和 SingleThread:

    允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

  2)CachedThreadPool和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
5. 【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。

  正例:注意线程安全,使用DateUtils。亦推荐如下处理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
    @Overrideprotected DateFormat initialValue() {return new SimpleDateFormat("yyyy-MM-dd");
    }
 }

说明:如果是JDK8的应用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替Simpledateformatter,官方给出的解释:simple beautiful strong immutable thread-safe。

6. 【强制】高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。
7. 【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。

  说明:线程一需要对表A、B、C依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是A、B、C,否则可能出现死锁。
8. 【强制】并发修改同一记录时,避免更新丢失,要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用version作为更新依据。

  说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。
9. 【强制】多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。
10. 【推荐】使用CountDownLatch进行异步转同步操作,每个线程退出前必须调用countDown方法,线程执行代码注意catch异常,确保countDown方法可以执行,避免主线程无法执行至countDown方法,直到超时才返回结果。

  说明:注意,子线程抛出异常堆栈,不能在主线程try-catch到。
11. 【推荐】避免Random实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 导致的性能下降。
  说明:Random实例包括java.util.Random 的实例或者 Math.random()实例。

  正例:在JDK7之后,可以直接使用API ThreadLocalRandom,在 JDK7之前,可以做到每个线程一个实例。
12. 【推荐】通过双重检查锁(double-checked locking)(在并发场景)实现延迟初始化的优化问题隐患(可参考 The "Double-Checked Locking is Broken" Declaration),推荐问题解决方案中较为简单一种(适用于JDK5及以上版本),将目标属性声明为 volatile型。

反例:

class Foo {private Helper helper = null;public Helper getHelper() {if (helper == null)synchronized (this) {if (helper == null)
                    helper = new Helper();
            }return helper;
    }// other functions and members...}

13. [참고] Volatile은 멀티 스레드에서 보이지 않는 메모리 문제를 해결합니다. 한 번의 쓰기와 많은 읽기의 경우 변수 동기화 문제는 해결되지만 쓰기가 많은 경우 스레드 안전성 문제는 해결되지 않습니다. count++ 연산인 경우 다음 클래스를 사용하여 구현합니다. AtomicInteger count = new AtomicInteger(); count.addAndGet(1); JDK8인 경우 AtomicLong보다 성능이 좋은 LongAdder 객체를 사용하는 것이 좋습니다. (낙관적 잠금 재시도 횟수가 줄어듭니다.)

14. [참고] HashMap의 크기 조정 용량이 부족할 경우 높은 동시성으로 인해 데드링크가 발생하여 개발 과정에서 이러한 위험이 발생하지 않도록 주의하세요.
15. [참고] ThreadLocal은 공유 객체의 업데이트 문제를 해결할 수 없습니다. ThreadLocal 객체에 대해서는 정적 수정을 사용하는 것이 좋습니다. 이 변수는 스레드 내의 모든 작업에 공통적이므로 정적 변수로 설정됩니다. 이러한 모든 인스턴스는 이 정적 변수를 공유합니다. 즉, 클래스가 처음 사용될 때 해당 클래스가 로드되고 저장소의 일부만 됩니다. 공간이 할당됩니다. 개체(이 스레드 내에 정의되어 있는 한)는 이 변수를 조작할 수 있습니다.

(7) 제어문

1. [필수] 스위치 블록 내에서 각 케이스는 중단/반환 등으로 종료되거나 프로그램이 스위치 블록 내에서 계속 실행될 것인지 나타내는 주석이어야 합니다. , 기본 문을 포함해야 하며 코드가 없더라도 끝에 배치되어야 합니다.
2. [필수] if/else/for/while/do 문에는 중괄호를 사용해야 합니다. 코드가 한 줄뿐이라도 다음 형식은 사용하지 마세요.
3. 가능한 한 적게 사용하는 것이 좋습니다. if-else 메서드는 다음과 같이 다시 작성할 수 있습니다.
 if(condition){
  ...
  return obj;
 }
  // 그런 다음 else 비즈니스 논리 코드를 작성합니다.
참고: if()... Else if()...else...를 사용해야 하는 경우 논리를 표현한다는 의미입니다. [필수] 3레벨을 초과하지 말고, 3레벨을 초과하는 경우 상태 디자인 패턴을 사용하세요.
  긍정적인 예: 3개 이상의 논리 수준을 갖춘 If-else 코드는 가드 문이나 상태 패턴을 사용하여 구현할 수 있습니다.
4. [권장] 일반적인 메소드(예: getXxx/isXxx)를 제외하고 조건 판단에서 다른 복잡한 명령문을 실행하지 말고, 가독성을 높이기 위해 복잡한 논리적 판단의 결과를 의미 있는 부울 변수 이름에 할당하십시오.

 참고: 많은 if 문의 논리는 매우 복잡합니다. 독자는 어떤 조건이 어떤 문을 실행하는지 알기 위해 조건식의 최종 결과를 분석해야 합니다. 따라서 독자가 논리식을 잘못 분석하면 어떻게 될까요?

  긍정적인 예:
   //의사코드는 다음과 같습니다
  boolean presents = (file.open(fileName, "w") != null) && (...) || (...);
  if (existed ) {
   ...
  }
  카운터 예:
  if ((file.open(fileName, "w") != null) && (...) || (...)) {
   ...
}
5 [권장사항] 루프 본문의 문은 성능을 고려해야 합니다. 객체 정의, 변수 가져오기, 불필요한 try-catch 작업 수행 등 처리를 위해 루프 외부로 이동해 보세요. -체외에서 루프로 이동하시겠습니까?
6. [권장] 인터페이스 매개변수 보호 이 시나리오는 일괄 작업에 사용되는 인터페이스에 일반적입니다.
7. [참고] 메소드에서 매개변수 검증이 필요한 시나리오:

 1) 자주 호출되는 메소드.

  2) 실행 시간이 많이 필요한 메소드의 경우 매개변수 검증 시간은 거의 무시할 수 있지만 매개변수 오류로 인해 중간 실행이 롤백되거나 오류가 발생하는 경우 이득이 손실보다 큽니다.
 3) 매우 높은 안정성과 가용성이 요구되는 방식입니다.

 4) RPC/API/HTTP 인터페이스 등 외부 세계에 제공되는 개방형 인터페이스입니다.
 5) 민감한 권한 출입입니다.
8. [참고] 메소드에서 매개변수 검증이 필요하지 않은 시나리오:

 1) 주기적으로 호출될 가능성이 높은 메소드에 대해서는 매개변수 검증을 권장하지 않습니다. 그러나 외부 매개변수 확인은 메소드 설명에 기록되어야 합니다.

 2) 기본 메서드는 자주 호출되며 일반적으로 확인되지 않습니다. 결국 이는 순수한 물 여과의 마지막 단계와 같으며, 매개변수 오류는 바닥층에 도달할 때까지 문제를 드러내지 않을 것입니다. 일반적으로 DAO 레이어와 서비스 레이어는 동일한 애플리케이션에 있고 동일한 서버에 배포되므로 DAO 매개변수 확인은 생략될 수 있습니다.

  3) private으로 선언된 메소드는 자신의 코드에서만 호출됩니다. 메소드를 호출하는 코드에서 전달된 매개변수가 확인되었거나 확실히 문제가 없는 경우에는 확인할 필요가 없습니다. 이때 매개변수입니다.

(8) 주석 규칙

1. [필수] 클래스, 클래스 속성, 클래스 메소드에 대한 주석은 /**콘텐츠*/ 형식을 사용하는 Javadoc 사양을 사용해야 하며, //xxx 메소드는 허용되지 않습니다. .

 참고: IDE 편집 창에서 Javadoc 모드는 관련 주석을 표시하며, 생성된 Javadoc은 프로젝트가 메서드를 호출할 때 해당 메서드, 매개 변수 및 반환의 의미를 IDE에 올바르게 출력할 수 있습니다. 메소드에 들어가지 않고도 값을 정지할 수 있습니다. 읽기 효율성이 향상됩니다.
2. [필수] 모든 추상 메소드(인터페이스의 메소드 포함)에는 반환 값, 매개변수 및 예외 설명 외에도 메소드가 수행하는 작업과 구현하는 기능이 표시되어야 합니다.

 참고: 서브클래스 구현 요구사항이나 호출 시 주의사항을 설명해 주세요.
3. [필수] 모든 클래스는 크리에이터 정보를 필수로 입력해야 합니다.
4. [필수] 메서드 내부에 한 줄 주석을 달고, 주석 처리된 문 위에 새 줄을 시작하고 //comment를 사용합니다. 메소드 내 여러 줄 주석에는 /* */ 주석을 사용하고 코드에 맞게 정렬하십시오.
5. [필수] 모든 열거 유형 필드에는 각 데이터 항목의 목적을 설명하는 설명이 있어야 합니다.
6. [추천] 어설프게 영어로 댓글을 달기보다는 중국어 댓글을 사용하여 문제를 명확하게 설명하는 것이 좋습니다. 고유명사와 키워드는 영어 원문에 그대로 남을 수 있습니다.

카운터 예: "TCP 연결 시간 초과"는 "전송 제어 프로토콜 연결 시간 초과"로 해석되는데, 이는 이해하기 더 어렵습니다.
7. [권장] 코드 수정 시 그에 맞춰 주석도 수정해야 하며, 특히 매개변수, 반환 값, 예외, 핵심 로직 등을 수정해야 합니다.

 참고: 도로망 및 내비게이션 소프트웨어 업데이트가 동기화되지 않은 것처럼 코드 및 주석 업데이트도 동기화되지 않습니다. 내비게이션 소프트웨어가 심각하게 지연되면 내비게이션의 의미가 상실됩니다.
8. [참고] 주석 처리된 코드는 단순히 주석 처리가 아닌 설명과 최대한 일치해야 합니다.

 참고: 코드를 주석 처리하는 데는 두 가지 가능성이 있습니다.

  1) 이 코드의 논리는 나중에 복원됩니다.

  2) 절대 사용하지 마세요. 전자에 코멘트 정보가 없으면 주석을 달게 된 동기를 알기 어렵다. 후자는 직접 삭제하는 것이 좋습니다(코드 저장소는 기록 코드를 저장합니다).
9. [참고] 댓글 요구사항:

 첫째, 디자인 아이디어와 코드 로직을 정확하게 반영할 수 있습니다.

 둘째, 비즈니스 의미를 설명할 수 있어 다른 프로그래머가 코드 이면의 정보를 빠르게 이해할 수 있습니다. 주석이 없는 큰 코드 블록은 독자에게 신성한 책과 같습니다. 주석은 오랜 시간이 지나도 그 당시의 생각을 명확하게 이해할 수 있도록 하기 위한 것입니다. , 그들이 귀하의 작업을 신속하게 인수할 수 있도록 합니다.
10. [참고] 좋은 이름 지정과 코드 구조는 설명이 필요하며, 댓글은 간결하고 정확하며 표현력이 풍부해야 합니다. 극단적인 주석을 피하십시오. 주석이 너무 많고 과도한 경우 코드의 논리가 수정되면 주석을 수정하는 것이 상당한 부담이 됩니다.

카운터 예:
// put Elephant into 냉장고
put(elephant, frigger)
put 메소드 이름과 두 개의 의미 있는 변수 이름 Elephant 및 bridge는 이미 이것이 수행하는 작업을 설명했으며 명확한 의미를 가진 코드는 다음과 같습니다. 추가 설명이 필요하지 않습니다.
11. [참고] 특수댓글 표시는 표시한 사람과 표시한 시간을 표시해 주세요. 이러한 마크를 적시에 처리하도록 주의하고 마크 스캔을 통해 자주 청소하십시오. 온라인 오류는 때때로 이러한 표시의 코드에서 발생합니다.

 1) 할 일 항목(TODO) : (사람 표시, 시간 표시, [예상 처리 시간]) 구현해야 하지만 아직 구현되지 않은 기능을 나타냅니다. 이는 실제로 Javadoc 태그입니다. 현재 Javadoc은 아직 구현되지 않았지만 널리 사용되었습니다. 클래스, 인터페이스 및 메소드에만 적용할 수 있습니다(Javadoc 태그이기 때문입니다). 2) 오류, 작동할 수 없음(FIXME): (사람 표시, 시간 표시, [예상 처리 시간]) 주석에 FIXME를 사용하여 특정 코드가 잘못되어 작동할 수 없으며 적시에 수정해야 함을 표시합니다.

(9) 기타

1. [필수] 정규식을 사용할 때 사전 컴파일 기능을 잘 활용하면 정규식 일치 속도를 효과적으로 높일 수 있습니다.

 참고: 메소드 본문에 정의하지 마십시오: 패턴 패턴 = Pattern.compile(rule);
2. [필수] 속도가 POJO 클래스의 속성을 호출할 때 속성 이름을 직접 사용하여 가져오는 것이 좋습니다. 값을 지정하고 템플릿 엔진은 자동으로 사양을 따릅니다. POJO의 getXxx()를 호출하면 그것이 부울 기본 데이터 유형 변수(부울 이름 앞에 is가 붙을 필요가 없음)인 경우 isXxx() 메서드가 자동으로 호출됩니다.

 참고: 부울 래퍼 클래스 객체인 경우 getXxx() 메서드가 먼저 호출됩니다.
3. [필수] 백그라운드에서 페이지로 전송되는 변수는 중간에 느낌표인 $!{var}를 추가해야 합니다.

 참고: var=null이거나 존재하지 않는 경우 ${var}가 페이지에 직접 표시됩니다.
4. [필수] Math.random()은 double 유형을 반환합니다. 값 범위는 0≤x<1입니다(0 값을 얻을 수 있으므로 0으로 나누기 예외에 유의하세요). 정수형의 난수를 얻으려면 x를 10의 여러 배로 확대한 다음 반올림하지 말고 Random 객체의 nextInt 또는 nextLong 메소드를 직접 사용하십시오.
5. [필수] new Date().getTime(); 대신 System.currentTimeMillis();를 사용하여 현재 밀리초 수를 가져옵니다.

  참고: 보다 정확한 나노초 시간 값을 얻으려면 System.nanoTime을 사용하세요. (). JDK8에서는 통계 시간과 같은 시나리오에 Instant 클래스를 사용하는 것이 좋습니다.
6. [권장 사항] vm 템플릿에 복잡한 논리는 물론 변수 선언과 논리 연산자를 추가하지 마세요.
7. [권장 사항] 데이터 구조의 무한한 증가와 메모리 소모를 방지하려면 데이터 구조를 구성하거나 초기화할 때 크기를 지정해야 합니다.
8. [권장사항] 메소드, 변수, 클래스, 구성 파일, 동적 구성 속성 등과 같이 "명확히 사용되지 않는 코드 및 구성"의 경우 프로그램에서 이를 제거하여 너무 많은 문제가 발생하지 않도록 해야 합니다. 많은 쓰레기.

2. 예외 로그

(1) 예외 처리

1. [필수] RuntimeException에서 상속되는 Java 클래스 라이브러리에 정의된 런타임 예외 클래스를 포착하지 마십시오. 이러한 예외는 다음과 같이 사전 확인됩니다. 프로그래머는 프로그램의 견고성을 우회하고 보장합니다.

  긍정적인 예: if(obj != null) {...}

  반대 예: try { obj.method() } catch(NullPointerException e){...}
2. 프로세스 제어, 조건 제어. 예외 처리 효율성이 조건 분기보다 낮기 때문입니다.
3. [필수] 무책임한 코드 부분을 잡아보세요. 캐치할 때 안정적인 코드와 불안정한 코드를 구분하시기 바랍니다. 안정적인 코드란 무슨 일이 있어도 잘못되지 않는 코드를 말합니다. 불안정한 코드를 잡기 위해서는 예외 유형을 최대한 구별한 후 해당 예외를 처리하도록 노력하세요.
4. [필수] 예외를 잡아서 처리하지 말고 처리하지 말고 예외를 호출자에게 던져주세요. 가장 바깥쪽에 있는 비즈니스 사용자는 예외를 처리하고 이를 사용자가 이해할 수 있는 콘텐츠로 변환해야 합니다.
5. [필수] 트랜잭션 코드에 try 블록을 넣습니다. 예외를 catch한 후 트랜잭션을 롤백해야 하는 경우 트랜잭션을 수동으로 롤백해야 합니다.
6. [필수] finally 블록은 리소스 개체와 스트림 개체를 닫아야 하며 예외가 있는 경우 try-catch해야 합니다.

 참고: JDK7의 경우 try-with-resources 방법을 사용할 수 있습니다.
7. [필수] finally 블록에서는 Return을 사용할 수 없습니다. finally 블록의 return이 반환된 후에는 메서드 실행이 종료되고 try 블록의 return 문이 실행되지 않습니다.
8. [필수] 잡힌 예외와 던져진 예외는 정확히 일치해야 합니다. 그렇지 않으면 잡힌 예외는 던져진 예외의 상위 클래스여야 합니다.

 참고: 상대가 수국 공을 던질 것으로 예상했지만 실제로 포환던지기를 받으면 예상치 못한 상황이 발생합니다.
9. [권장 사항] 메서드의 반환 값은 null일 수 있습니다. 빈 컬렉션이나 빈 개체를 반환하는 것은 필수가 아닙니다. 어떤 상황에서 null 값이 반환되는지 자세히 설명하려면 주석을 추가해야 합니다. 호출자는 NPE 문제를 방지하기 위해 null 판단을 수행해야 합니다.

 참고: 이 프로토콜에서는 NPE를 예방하는 것이 발신자의 책임임을 명확하게 명시합니다. 호출된 메서드가 빈 컬렉션이나 빈 개체를 반환하더라도 호출자에게는 걱정할 필요가 없는 상황입니다. 원격 호출 실패, 런타임 예외 등의 시나리오에서 null이 반환되는 상황을 고려해야 합니다.
10. [권장사항] NPE 예방은 프로그래머의 기본 교육입니다. NPE가 발생하는 시나리오에 주의하세요.

 1) 반환 유형은 압축된 데이터 유형이므로 int 값을 반환할 때 주의하세요. null 값으로.

 카운터 예: public int f(){ return Integer object}; null인 경우 자동으로 unboxing되고 NPE가 발생합니다.

 2) 데이터베이스의 쿼리 결과가 null일 수 있습니다.

 3) 컬렉션의 요소가 isNotEmpty인 경우에도 가져온 데이터 요소는 null일 수 있습니다.
 4) 원격통화로 반송된 물건에 대해서는 NPE 판단이 필요합니다.

 5) Session에서 얻은 데이터는 Null 포인터를 피하기 위해 NPE를 확인하는 것이 좋습니다.

 6) obj.getA().getB().getC();에 대한 연속 호출은 쉽게 NPE를 유발할 수 있습니다.
11. [권장사항] 코드에 "예외 발생" 또는 "오류 코드 반환"을 사용할지 여부. 회사 외부의 http/api 개방형 인터페이스의 경우 애플리케이션 내에서 "오류 코드"를 사용해야 합니다. 애플리케이션 간 RPC는 isSuccess, "오류 코드" 및 "오류 요약 정보"를 캡슐화하기 위해 Result 메서드를 사용하여 Prioritize를 호출합니다. 참고: RPC 메서드 반환에 Result 메서드를 사용하는 이유:

 1) 예외 반환 메서드를 사용하면 호출자가 이를 catch하지 못할 경우 런타임 오류가 발생합니다.

 2) 스택 정보를 추가하지 않고 새로운 사용자 정의 예외를 추가하고 오류 메시지에 대한 자신의 이해를 추가하면 호출 측에서 문제를 해결하는 데 큰 도움이 되지 않습니다. 스택 정보를 추가하면 잦은 호출 오류의 경우 데이터 직렬화 및 전송 성능 손실도 문제가 된다.
12. [권장사항] 정의 시 unchecked/checked 예외를 구별하고, RuntimeException을 사용하여 직접 throw하는 것을 피하고, 비즈니스 의미가 있는 Custom 예외를 사용하지 않아야 합니다. DAOException / ServiceException 등 업계에서 정의된 커스텀 예외를 권장합니다.
13. [참고] 중복 코드를 피하세요(Don't Repeat Yourself), 즉 DRY 원칙입니다. 참고: 코드를 마음대로 복사하고 붙여넣으면 필연적으로 코드 중복이 발생합니다. 나중에 수정이 필요한 경우 모든 복사본을 수정해야 하는데 이는 놓치기 쉽습니다. 필요한 경우 공통 메소드, 추상 공용 클래스 또는 공유 모듈을 추출하십시오.

  긍정적인 예: 클래스에는 여러 공개 메소드가 있으며 모두 동일한 매개변수 확인 작업의 여러 행을 수행해야 합니다. 이때 다음을 추출하세요.
  private boolean checkParam(DTO dto){...}

(2) 로그 프로토콜

1. [필수] 애플리케이션은 로그 시스템(Log4j, Logback)에서 API를 직접 사용할 수 없으며, 로그 프레임워크 SLF4J의 API에 의존해야 합니다. 각 클래스의 로그 처리 방식이 통일되어 있습니다.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 private static final Logger logger = LoggerFactory.getLogger(Abc.class);
2 [필수] 최소 15일 동안 로그 파일을 저장하는 것이 좋습니다. , 일부 예외가 있기 때문에 "주"는 주파수 특성입니다.
3. [필수] 애플리케이션의 확장 로그(예: 관리, 임시 모니터링, 액세스 로그 등)에 대한 명명 방법: appName_logType_logName.log. logType: 로그 유형, 권장 카테고리에는 stats/desc/monitor/visit 등이 포함됩니다. logName: 로그 설명. 이런 이름 지정의 장점은 파일 이름을 통해 해당 로그 파일이 어떤 애플리케이션에 속해 있는지, 어떤 유형인지, 어떤 용도인지 알 수 있어 분류 및 검색에도 도움이 됩니다.

  긍정적인 예: mppserver_monitor_timeZoneConvert.log와 같은 mppserver 애플리케이션에서 시간대 변환 예외를 별도로 모니터링합니다. 참고: 오류 로그와 비즈니스 로그는 가능한 한 별도로 분류하여 저장하는 것이 좋습니다. 개발자가 볼 수 있으며, 로그를 통해 시스템을 적시에 모니터링하는 데도 편리합니다.
4. [필수] 추적/디버그/정보 수준 로그 출력의 경우 조건부 출력 형식을 사용하거나 자리 표시자를 사용해야 합니다.

 설명: logger.debug("ID로 거래 처리 중: " + id + " 기호: " + 기호); 로그 수준이 경고인 경우 위 로그는 인쇄되지 않지만 문자열 접합 작업이 수행됩니다. 기호가 object 인 경우 toString() 메서드가 실행되어 시스템 리소스가 낭비됩니다. 위 작업을 수행한 후 최종 로그가 인쇄되지 않습니다.

 긍정적 예: (조건)
 if (logger.isDebugEnabled()) {
  logger.debug("ID로 거래 처리 중: " + id + " 기호: " + 기호);
 }
 긍정적 예: (자리 표시자 기호 )
 logger.debug("ID: {} 기호: {} ", id, 기호);
5. [필수] 로그를 반복적으로 인쇄하고 디스크 공간을 낭비하지 않으려면 log4j에서 additivity=를 설정해야 합니다. xml 거짓입니다.

  긍정적인 예:
6. [필수] 예외 정보에는 범죄 현장 정보와 예외 스택 정보라는 두 가지 유형의 정보가 포함되어야 합니다. 그렇지 않다면 던져 버리세요.

  긍정적인 예: logger.error(다양한 매개변수 또는 객체 toString + "_" + e.getMessage(), e);
7. [권장] 경고 로그 수준을 사용하여 사용자 입력 매개변수 오류를 기록할 수 있습니다. 사용자는 불평하고 손실을 입습니다. 로그 출력 수준에 주의하세요. 오류 수준은 시스템 논리 오류 및 예외와 같은 중요한 오류 정보만 기록합니다. 필요하지 않은 경우 이 시나리오에서는 오류 수준을 입력하지 마십시오.
8. [권장] 로그를 꼼꼼히 기록하세요. 프로덕션 환경에서는 디버그 로그를 출력하는 것이 금지되어 있습니다. 경고를 사용하여 처음 시작할 때 비즈니스 동작 정보를 기록하는 경우 서버 디스크가 버스트되지 않도록 로그 출력량에 주의해야 합니다. 이러한 관찰 로그를 제때 삭제하는 것을 잊지 마세요.

 참고: 잘못된 로그를 대량으로 출력하는 것은 시스템 성능을 향상하거나 오류 지점을 빠르게 찾는 데 도움이 되지 않습니다. 로그를 기록할 때 다음 사항을 생각해 보십시오. 실제로 이 로그를 읽는 사람이 있습니까? 이 로그를 본 후 무엇을 할 수 있나요? 문제 해결에 이점을 가져올 수 있습니까?

3. MySQL 사양

(1) 테이블 생성 사양

1. [필수] yes 또는 no 개념을 표현하는 필드는 is_xxx를 사용하여 이름을 지정해야 하며, 데이터 유형은 unsignedtinyint(1은 yes, 0은 의미) 아니요) 이 규칙은 odps 테이블 생성에도 적용됩니다.

 참고: 필드가 음수가 아닌 경우 부호가 없어야 합니다.
2. [필수] 테이블 이름과 필드 이름은 반드시 소문자 또는 숫자를 사용해야 하며, 처음에는 숫자를 사용할 수 없으며 밑줄 두 개 사이의 숫자만 사용할 수 있습니다. 데이터베이스 필드 이름을 수정하는 것은 시험판이 불가능하므로 비용이 매우 많이 들기 때문에 필드 이름을 신중하게 고려해야 합니다.

  긍정적인 예: getter_admin, task_config, level3_name

  카운터 예: GetterAdmin, taskConfig, level_3_name
3. [필수] 테이블 이름에 복수 명사를 사용하지 마세요. 참고: 테이블 이름은 테이블의 엔터티 내용만 나타내야 하며 해당 DO 클래스 이름도 표현 습관과 일치하는 단수형이어야 합니다.
4. [필수] desc, range, match, Delay 등 예약어를 비활성화합니다. MySQL 공식 예약어를 참고하세요.
5. [필수] 고유 인덱스 이름은 uk_field 이름이고, 공통 인덱스 이름은 idx_field 이름입니다. 참고: uk_는 고유 키이고 idx_는 index의 약어입니다.
6. [필수] 소수형은 10진수이며, float, double은 금지됩니다.

 참고: float 및 double을 저장할 때 정밀도가 손실되는 문제가 있으며, 값을 비교할 때 잘못된 결과를 얻을 수 있습니다. 저장되는 데이터의 범위가 소수점 이하의 범위를 초과하는 경우, 데이터를 정수와 소수로 분리하여 별도로 저장하는 것이 좋습니다.
7. [필수] 저장된 문자열의 길이가 거의 같은 경우 char 고정 길이 문자열 유형을 사용하십시오.
8. [필수] Varchar는 가변 길이 문자열이며 미리 할당된 저장 공간이 없습니다. 길이는 5000을 초과할 수 없습니다. 저장 길이가 이 값보다 큰 경우 필드 유형을 텍스트로 정의하고 별도의 테이블을 생성합니다. , 다른 필드의 인덱스 효율성에 영향을 미치지 않도록 해당 기본 키를 사용합니다.
9. [필수] 테이블에는 id, gmt_create, gmt_modified의 세 가지 필드가 있어야 합니다.

 참고: ID는 기본 키여야 하며 유형은 unsigned bigint, 단일 테이블에 대한 자동 증가, 단계 크기는 1입니다. gmt_create 및 gmt_modified 유형은 모두 date_time 유형입니다.
10. [추천] 테이블 이름은 "업체명_테이블의 기능"으로 지정하는 것이 가장 좋습니다. 긍정적인 예: Tiger_task / Tiger_reader / mpp_config
11. [권장 사항] 라이브러리 이름과 애플리케이션 이름은 최대한 일관되어야 합니다.
12. [권장사항] 필드의 의미를 수정하거나 필드가 나타내는 상태를 추가하는 경우 적시에 필드 댓글을 업데이트해야 합니다.
13. [권장] 성능 향상을 위해 필드에 적절한 중복성을 허용하지만 데이터 동기화를 고려해야 합니다. 중복 필드는 다음을 따라야 합니다.

 1) 자주 수정되지 않는 필드. 2) 텍스트 필드는 물론 varchar 초장형 필드도 아닙니다.

   긍정적인 예: 제품 카테고리 이름이 자주 사용되며 필드 길이가 짧고 이름이 기본적으로 변경되지 않습니다. 카테고리 이름은 관련 쿼리를 피하기 위해 관련 테이블에 중복 저장될 수 있습니다.
14. [권장사항] 데이터베이스 및 테이블 샤딩은 단일 테이블의 행 수가 500만 개를 초과하거나 단일 테이블의 용량이 2GB를 초과하는 경우에만 권장됩니다.

 참고: 데이터 양이 3년 내에 이 수준에 도달하지 않을 것으로 예상되면 테이블 생성 시 데이터베이스를 테이블로 나누지 마십시오.
15. [참고] 적절한 문자 저장 길이는 데이터베이스 테이블 공간과 인덱스 저장 공간을 절약할 뿐만 아니라, 더 중요한 것은 검색 속도를 향상시킵니다.

  긍정적인 예: 사람의 나이에는 부호 없는tinyint를 사용합니다(범위 0-255를 나타냄, 사람의 수명은 255년을 초과하지 않음). 거북이는 smallint여야 하지만 태양 나이인 경우 int여야 하며, 모두 별이면 나이를 더한 다음 bigint를 사용해야 합니다.

(2) 인덱스 사양

1. [필수] 비즈니스에서 고유한 특성을 갖는 필드는 결합된 필드라도 고유한 인덱스로 구성되어야 합니다.

 참고: 고유 인덱스가 삽입 속도에 영향을 미친다고 생각하지 마십시오. 이러한 속도 손실은 무시할 수 있지만, 애플리케이션 계층에서 매우 완벽한 체크섬 제어가 수행되더라도 검색 속도의 증가는 명백합니다. Mo에 따르면 고유 인덱스가 없는 한 수수료 법칙에 따라 더티 데이터가 생성되어야 합니다.
2. [필수] 3개 이상의 테이블 참여는 금지됩니다. 조인해야 하는 필드의 데이터 유형은 절대적으로 일관되어야 합니다. 다중 테이블 상관 관계를 쿼리할 때 상관 관계가 있는 필드에 인덱스가 있어야 합니다.

 참고: 더블 테이블 조인 시에도 테이블 인덱스와 SQL 성능에 주의해야 합니다.
3. [필수] varchar 필드에 인덱스를 생성할 때 인덱스 길이를 지정해야 합니다. 인덱스 길이는 실제 텍스트 구분에 따라 결정됩니다.

 참고: 인덱스 길이와 구별은 모순된 쌍입니다. 일반적으로 문자열 유형 데이터의 경우 길이가 20인 인덱스의 경우 구별이 90% 이상 높아집니다. count(distinct left(column)를 사용할 수 있습니다. 이름, 인덱스 길이) )/개수(*).
4. [필수] 페이지 검색 시 왼쪽 흐림 또는 전체 흐림 사용을 엄격히 금지합니다. 필요한 경우 검색 엔진을 사용하여 문제를 해결하세요.

 참고: 인덱스 파일에는 B-Tree의 가장 왼쪽 접두사 일치 기능이 있습니다. 왼쪽의 값이 결정되지 않으면 이 인덱스를 사용할 수 없습니다.
5. [추천] 시나리오별 순서가 있는 경우, 인덱스의 질서에 주의해주세요. order by의 마지막 필드는 결합된 인덱스의 일부이며 file_sort를 방지하고 쿼리 성능에 영향을 미치기 위해 인덱스 조합 순서의 끝에 배치됩니다.

 긍정적 예: a=? 및 b=? 순서: 인덱스: a_b_c

 카운터 예: 인덱스에 범위 검색이 있는 경우 다음과 같이 인덱스 순서를 사용할 수 없습니다. ORDER BY b; 인덱스 a_b 정렬할 수 없습니다.
6. [권장] 테이블 반환 작업을 방지하려면 커버링 인덱스를 사용하여 쿼리 작업을 수행하세요.

 설명: 책이 11장의 제목을 알아야 한다면 11장에 해당하는 페이지가 열리나요? 디렉토리를 찾아보세요. 이 디렉토리는 포함 색인 역할을 합니다.

  긍정적인 예: 생성할 수 있는 인덱스 유형: 기본 키 인덱스, 고유 인덱스, 일반 인덱스 및 커버링 인덱스는 쿼리의 효과로 설명 결과에 인덱스를 사용하여 추가 열이 나타납니다.
7. [권장] 다중 페이지 페이징 시나리오를 최적화하려면 지연된 상관 관계 또는 하위 쿼리를 사용하세요.

 설명: MySQL은 오프셋 행을 건너뛰지 않고 오프셋+N 행을 취한 다음 포기하기 전에 오프셋 행을 반환하고, 오프셋이 특히 크면 효율성이 매우 낮거나 총 개수가 반환됩니다. 페이지 수를 제어하거나 특정 임계값을 초과하는 페이지 수에 대해 SQL 재작성을 수행합니다.

  긍정적인 예: 먼저 획득해야 하는 id 세그먼트를 빠르게 찾은 다음 연결합니다. SELECT a.* FROM table 1 a, (조건이 LIMIT 100000,20인 테이블 1에서 id 선택) b where a.id=b. id
8 . [추천] SQL 성능 최적화의 목표: 최소한 범위 수준에 도달하고, 요구 사항은 참조 수준이며, 상수일 수 있으면 가장 좋습니다.

 지침:

  1) Consts 단일 테이블에는 최대 하나의 일치하는 행(기본 키 또는 고유 인덱스)이 있으며 최적화 단계에서 데이터를 읽을 수 있습니다.

  2) ref는 일반 인덱스를 사용하는 것을 의미합니다.

  3) range는 인덱스에 대해 범위 검색을 수행합니다.

카운터 예: explain 테이블 type=index의 결과는 인덱스 실제 파일의 전체 스캔이며 이는 매우 느립니다. 이 인덱스 수준은 범위보다 낮으며 전체 테이블 스캔에 비하면 왜소합니다.
9. [권장사항] 결합형 인덱스를 구축할 때 가장 차별화된 인덱스는 가장 왼쪽에 있습니다. 긍정적인 예: a=? 및 b=?에서 a 열이 고유 값에 거의 가까우면 단일 idx_a 인덱스만 생성하면 됩니다.

 참고: 등호가 아닌 기호와 등호가 혼합된 판단 조건이 있는 경우, 인덱스 구축 시 등호 조건의 열을 앞에 두시기 바랍니다. 예를 들어, a>? 및 b=? 그러면 a가 더 높은 구별도를 가지더라도 b는 인덱스의 맨 앞에 배치되어야 합니다.
10. [참고] 인덱스 생성 시 다음과 같은 극단적인 오해를 피하세요.

 1) 쿼리에 인덱스가 필요하다는 오해.

 2) 인덱싱이 공간을 소비하고 업데이트 및 새로운 추가 속도를 심각하게 느리게 한다는 오해.

 3) 고유 인덱스는 항상 "먼저 확인하고 삽입"하는 방법을 통해 애플리케이션 계층에서 해결해야 한다고 잘못 믿고 있습니다.

(3) SQL 사양

1. [필수] count(*) 대신 count(*)를 사용하지 마세요. count(*)는 SQL92에서 정의한 표준 구문입니다. 데이터베이스와 동일합니다. NULL 및 NULL이 아닌 것과는 아무 관련이 없습니다.

 참고: count(*)는 NULL 값이 있는 행의 개수를 계산하지만, count(열 이름)는 이 열에서 NULL 값이 있는 행의 개수를 계산하지 않습니다.
2. [필수] count(distinct col) NULL을 제외한 열의 고유 숫자 개수를 계산합니다. count(distinct col1, col2)는 열 중 하나가 모두 NULL인 경우 다른 열의 값이 다르더라도 0을 반환합니다.
3. [필수] 특정 컬럼의 값이 모두 NULL인 경우 count(col)의 반환 결과는 0이지만 sum(col)의 반환 결과는 NULL이므로 주의가 필요합니다. sum()을 사용할 때 NPE 문제가 발생합니다.

긍정적인 예: 합계의 NPE 문제를 방지하려면 다음 방법을 사용할 수 있습니다. SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;
4 [필수] ISNULL()을 사용합니다. NULL 값인지 확인합니다. 참고: NULL을 임의의 값과 직접 비교하면 NULL이 반환됩니다.

 참고: 1) NULL<>NULL의 반환 결과는 false가 아닌 NULL입니다.

   2) NULL=NULL의 반환 결과는 true가 아닌 NULL입니다.

   3) NULL<>1의 반환 결과는 true가 아닌 NULL입니다.
5. [필수] 코드에 페이징 쿼리 로직을 작성할 때 개수가 0인 경우 후속 페이징 문 실행을 피하기 위해 직접 반환해야 합니다.
6. [필수] 외래 키 및 캐스케이드는 허용되지 않습니다. 모든 외래 키 개념은 애플리케이션 계층에서 해결되어야 합니다. 참고: (개념 설명) 학생 테이블의 Student_id가 기본 키이고, 성적 테이블의 Student_id가 외래 키입니다. 학생 테이블의 학생_ID가 업데이트되고 성적 테이블의 학생_ID가 동시에 업데이트되면 계단식 업데이트입니다. 외래 키 및 계단식 업데이트는 단일 시스템의 낮은 동시성에는 적합하지만 분산 및 동시성 클러스터에는 적합하지 않습니다. 계단식 업데이트는 데이터베이스 업데이트 폭풍의 위험이 있으며 데이터베이스 삽입 속도에 영향을 미칩니다. .
7. [필수] 저장 프로시저는 디버그 및 확장이 어렵고 이식성이 없습니다.
8. [필수] 데이터 수정 시, 기록을 삭제하거나 수정하는 경우 실수로 삭제되지 않도록 먼저 선택하고, 올바른지 확인한 후 업데이트 문을 실행해야 합니다.
9. [권장] 피할 수 없다면 피하세요. in 뒤에 있는 수집 요소 수를 신중하게 평가하고 1,000개 이내로 제어해야 합니다.
10. [참고] 세계화가 필요한 경우 모든 문자 저장 및 표현은 utf-8로 인코딩되며 문자 계산 방법에 유의하세요.

  설명: SELECT LENGTH ("Easy Work"); CHARACTER_LENGTH ("쉬운 작업"); 4로 반환됩니다. 이모티콘을 사용하려면 utfmb4를 사용하여 utf-8 인코딩의 차이점에 유의하세요.
11. [참고] TRUNCATE TABLE은 DELETE보다 빠르고 시스템 및 트랜잭션 로그 리소스를 덜 사용합니다. 그러나 TRUNCATE는 트랜잭션이 없으며 트리거를 트리거하지 않으므로 개발 시 이 문을 사용하지 않는 것이 좋습니다. 암호.

 참고: TRUNCATE TABLE은 WHERE 절이 없는 DELETE 문과 기능적으로 동일합니다.

(4) ORM 프로토콜

1. [필수] 쿼리의 필드 목록으로 *를 사용하지 마십시오. 어떤 필드가 필요한지 명확하게 명시해야 합니다.

 지침:

  1) 쿼리 분석기 구문 분석 비용을 늘립니다.

  2) 필드를 추가하거나 빼는 것은 resultMap 구성과 일치하지 않기 쉽습니다.
2. [필수] POJO 클래스의 부울 속성은 is로 추가할 수 없지만, 데이터베이스 필드는 is_로 추가해야 하며, 이는 resultMap의 필드와 속성 간의 매핑이 필요합니다.

 참고: POJO 클래스 정의 및 데이터베이스 필드 정의를 참조하세요. sql.xml에 매핑을 추가해야 합니다.
3. [필수] resultClass를 반환 매개변수로 사용하지 마세요. 모든 클래스 속성 이름이 데이터베이스 필드에 해당하더라도 반대로 정의해야 합니다. 각 테이블에는 그에 해당하는 이름이 있어야 합니다.

  설명: 쉬운 유지 관리를 위해 DO 클래스에서 필드를 분리하도록 매핑 관계를 구성합니다.
4. [필수] xml 구성에서 매개변수 사용에 주의하세요: #{}, #param# 이 방법은 SQL 주입이 발생하기 쉽습니다.
5. [필수] iBATIS에 포함된 queryForList(StringstatementName, int start, int size)는 권장하지 않습니다.

  설명: 구현 방법은 데이터베이스에서statementName에 해당하는 SQL 문의 모든 레코드를 얻은 다음 이러한 이유로 인해 온라인에서 subList를 통해 시작 및 크기의 하위 집합을 얻는 것입니다.
긍정적인 예: sqlmap에 #start#, #size#
를 도입하세요. .put("size", size);
6. [필수] 쿼리 결과 집합의 출력으로 HashMap 및 Hashtable을 직접 사용할 수 없습니다. .
7. [필수] 데이터 테이블 레코드 업데이트 시 해당 레코드의 gmt_modified 필드 값도 현재 시간으로 업데이트되어야 합니다.
8. [권장 사항] 크고 포괄적인 데이터 업데이트 인터페이스를 작성하지 마세요. POJO 클래스로 전달하세요. 자체 대상 업데이트 필드인지 여부에 관계없이 업데이트 테이블은 c1=value1,c2=value2,c3=value3입니다. ; 이건 옳지 않아요. SQL을 실행할 때 수정되지 않은 필드를 업데이트하지 마십시오. 첫째, 오류가 발생하기 쉽고 셋째, binlog가 저장 공간을 늘립니다.
9. [참고] @Transactional 거래를 남용하지 마세요. 트랜잭션은 데이터베이스의 QPS에 영향을 미칩니다. 또한 트랜잭션이 사용되는 경우 캐시 롤백, 검색 엔진 롤백, 메시지 보상, 통계 수정 등을 포함한 롤백 솔루션의 다양한 측면을 고려해야 합니다.
10. [참고] 의 CompareValue는 속성 값과 비교되는 상수로, 일반적으로 가 비어 있지 않을 때 실행됩니다. not null 은 값이 null이 아닌 경우 실행을 의미합니다.

IV.Engineering Spec

(1) 응용 계층화

1. [권장] 기본적으로 그림의 상위 레이어는 하위 레이어에 종속될 수 있음을 나타냅니다. 개방형 인터페이스 계층은 웹 계층에 종속되거나 서비스 계층에 직접적으로 종속될 수 있습니다.

 개방형 인터페이스 계층: 서비스 인터페이스는 웹을 통해 RPC 인터페이스로 직접 캡슐화되고 노출될 수 있습니다. 게이트웨이 제어 계층 등

 터미널 디스플레이 레이어: 각 터미널의 템플릿은 디스플레이 레이어를 렌더링하고 실행합니다. 현재 주요 렌더링으로는 벨로시티 렌더링, JS 렌더링, JSP 렌더링, 모바일 디스플레이 레이어 등이 있습니다.
 웹 계층: 주로 액세스 제어 전달, 다양한 기본 매개변수 확인 또는 단순히 재사용되지 않는 서비스 처리 등.
 서비스 계층: 상대적으로 구체적인 비즈니스 로직 서비스 계층입니다.
 관리자 레이어: 다음과 같은 특징을 갖는 일반 비즈니스 처리 레이어:

 1) 타사 플랫폼을 캡슐화하고 반환 결과를 전처리하고 예외 정보를 변환하는 레이어

 2) 서비스 레이어의 일반 기능을 싱크합니다. 캐싱 솔루션, 미들웨어 일반 처리

 3) DAO 레이어와 상호 작용하여 DAO의 일반적인 비즈니스 기능을 캡슐화합니다.

 DAO 레이어: 데이터를 위해 기본 MySQL, Oracle 및 Hbase와 상호 작용하는 데이터 액세스 레이어입니다.

 외부 인터페이스 또는 타사 플랫폼: 다른 부서의 RPC 개방형 인터페이스, 기본 플랫폼 및 다른 회사의 HTTP 인터페이스가 포함됩니다.
2. [참고] (계층적 예외 처리 프로토콜) DAO 계층에서는 다양한 유형의 예외가 발생하므로 catch(Exception e) 메서드를 사용하여 새로운 DAOException(e)을 발생시킵니다. . 로그를 캡처하여 Manager/Service 계층에서 로그 파일에 기록해야 하므로 로그를 인쇄할 필요가 없습니다. 동일한 서버에서 로그를 다시 인쇄하면 성능과 스토리지가 낭비됩니다. 서비스 계층에서 예외가 발생하면 로그 정보를 디스크에 기록해야 하며, 매개변수 정보도 최대한 포함해야 범죄 현장을 보호할 수 있다. Manager 계층과 서비스가 동일한 시스템에 배포된 경우 로깅 방법은 DAO 계층 처리와 일치합니다. 별도로 배포된 경우 로깅 방법은 서비스와 일치합니다. 웹 계층은 이미 최상위 수준에 있으므로 예외를 계속해서 발생시켜서는 안 됩니다. 이 예외로 인해 페이지가 정상적으로 렌더링되지 않는다는 것을 알게 되면 바로 다음 단계로 이동해야 합니다. 친숙한 오류 페이지를 확인하고 친숙한 오류 메시지를 추가해 보세요. 개방형 인터페이스 계층은 예외를 처리하고 이를 오류 코드 및 오류 메시지 형식으로 반환해야 합니다.
3. [참고] Hierarchical Domain Model 사양:
DO(Data Object): 데이터베이스 테이블 구조에 일대일로 대응하며, DAO 레이어를 통해 데이터 소스 객체를 상위로 전달한다.
 DTO(Data Transfer Object): 데이터 전송 객체, 서비스와 매니저가 외부로 전송하는 객체.
 BO(비즈니스 개체): 비즈니스 개체입니다. 비즈니스 로직을 캡슐화하고 서비스 계층에서 출력할 수 있는 개체입니다.
 QUERY: 데이터 쿼리 객체로, 각 계층은 상위 계층으로부터 쿼리 요청을 받습니다. 참고: 매개변수가 2개 이상인 쿼리 캡슐화에서는 전송에 Map 클래스를 사용할 수 없습니다.
 VO(View Object): 표시 레이어 개체, 일반적으로 웹을 통해 템플릿 렌더링 엔진 레이어로 전송되는 개체입니다.

(2) Two-party 라이브러리 사양

1. [필수] 다음 규칙을 준수하도록 GAV를 정의합니다.

 1) 그룹ID 형식: com.{Company/BU}.Business Line.[Sub-Business Line], 최대 4개 레벨.

   설명: {회사/BU} 예: alibaba/taobao/tmall/aliexpress 및 기타 BU 수준은 선택 사항입니다.

   긍정적인 예: com.taobao.jstorm 또는 com.alibaba.dubbo.register

  2) ArtifactID 형식: 제품군 이름-모듈 이름. 의미는 반복되거나 생략되지 않습니다. 먼저 창고 센터에 가서 확인하세요.

   긍정적인 예: dubbo-client / fastjson-api / jstorm-tool 3) 버전: 아래 세부 내용을 참고하세요.
2. [필수] 타사 라이브러리 버전 번호 명명 방법: 메이저 버전 번호. 마이너 버전 번호. 개정 번호

 1) 메이저 버전 번호: 호환되지 않는 API 수정이 있거나 제품 방향을 변경할 수 있는 새로운 기능이 있는 경우 추가됩니다.

 2) 마이너 버전 번호: 이전 버전과 호환되는 기능 추가(새 클래스, 인터페이스 등)로 처리됩니다.

 3) 개정 번호: 버그 수정, 메서드 시그니처 수정 없이 기능 향상, API 호환성 유지.

  참고: 시작 버전 번호는 0.0.1이 아닌 1.0.0이어야 합니다.
3. [필수] 온라인 애플리케이션은 SNAPSHOT 버전에 의존하지 않습니다(보안 패키지 제외). RELEASE 버전 번호 +1 방법이며 버전 번호는 덮어쓰기 및 업그레이드를 허용하지 않으므로 중앙 창고에 가서 확인해야 합니다.

 참고: SNAPSHOT 버전에 의존하지 않으면 애플리케이션 릴리스의 멱등성이 보장됩니다. 또한 컴파일하는 동안 패키징 및 구성 속도도 높일 수 있습니다.
4. [필수] 타사 라이브러리를 추가하거나 업그레이드해도 기능 포인트를 제외한 다른 jar 패키지의 중재 결과는 변경되지 않습니다. 변경사항이 있는 경우 명확하게 평가하고 검증해야 합니다. dependency:resolve 전후의 정보를 비교하는 것이 좋습니다. 중재 결과가 완전히 일치하지 않는 경우 dependency:tree 명령을 사용하여 차이점을 찾아 5. [필수] 타사 라이브러리는 열거형을 정의할 수 있고 매개변수는 열거형을 사용할 수 있지만 인터페이스 반환 값은 열거형 또는 열거형을 포함하는 POJO 객체의 사용을 허용하지 않습니다.
6. [필수] 타사 라이브러리 그룹에 의존하는 경우 버전 번호 불일치를 방지하기 위해 통합 버전 변수를 정의해야 합니다.

  설명: springframework-core, -context, -beans에 의존합니다. 버전을 저장하기 위해 변수를 정의할 수 있습니다: ${spring.version}. 의존성을 정의할 때 이 버전을 참조하세요.
7. [필수] 하위 프로젝트의 pom 종속성에 동일한 GroupId, 동일한 ArtifactId가 있지만 다른 버전을 갖는 것은 금지됩니다.

 참고: 로컬에서 디버깅하는 경우 각 하위 프로젝트에서 지정한 버전 번호가 사용되지만, war에 병합되면 최종 lib 디렉터리에 하나의 버전 번호만 나타날 수 있습니다. 오프라인 디버깅은 정확했지만 온라인으로 출시되었을 때 문제가 발생한 선례가 있었습니다.
8. [권장] 모든 pom 파일의 종속성 선언을 <종속성> 문 블록에 배치하고 모든 버전 조정을 <종속성 관리>

 참고: 는 버전만 선언하고 소개를 구현하지 않습니다. 따라서 하위 프로젝트는 상위 pom에서 종속성을 명시적으로 선언해야 합니다. 그리고 기본 pom의 에 선언된 모든 종속성은 기본적으로 모든 하위 프로젝트에 자동으로 도입되고 상속됩니다.
9. [권장 사항] 타사 라이브러리는 구성 항목을 갖지 않도록 노력해야 하며, 최소한 더 이상 구성 항목을 추가하지 않아야 합니다.
10. [참고] 타사 라이브러리 적용 시 종속성 충돌을 피하기 위해 타사 라이브러리 게시자는 다음 원칙을 따라야 합니다.

 1) 단순성과 제어 가능성의 원칙. 서비스 API, 필수 도메인 모델 개체, Utils 클래스, 상수, 열거형 등을 포함하여 불필요한 API 및 종속성을 모두 제거합니다. 다른 타사 라이브러리에 의존하는 경우 제공된 기능을 통해 해당 라이브러리를 도입해 보세요. 그러면 타사 라이브러리 사용자가 특정 버전 번호에 의존할 수 있습니다. 로그에 대한 구체적인 구현은 없으며 로그 프레임워크에만 의존합니다.

 2) 안정적인 추적성 원칙. 각 버전의 변경 사항을 기록해야 하며, 누가 타사 라이브러리를 유지 관리하는지, 소스 코드가 있는 위치는 모두 쉽게 액세스할 수 있어야 합니다. 사용자가 적극적으로 버전을 업그레이드하지 않는 한 공개 타사 라이브러리의 동작은 변경되어서는 안 됩니다.

(3) 서버 사양

1. [권장] 동시성이 높은 서버의 경우 TCP 프로토콜의 time_wait 타임아웃을 줄이는 것이 좋습니다. 참고: 기본적으로 운영 체제는 240초 후에 time_wait 상태에서 연결을 닫습니다. 동시 액세스가 많은 경우 time_wait에 연결이 너무 많아 서버가 새 연결을 설정하지 못할 수 있으므로 이 값을 조정해야 합니다. 서버에서 대기 값.

  긍정적인 예: Linux 서버에서 /etc/sysctl.conf 파일을 변경하여 기본값(초)을 수정하세요. net.ipv4.tcp_fin_timeout = 30
2 [권장] 서버에서 지원하는 최대 파일을 늘리세요. 핸들 수(파일 설명자, fd로 약칭)

 참고: 주류 운영 체제의 설계는 파일과 동일한 방식으로 TCP/UDP 연결을 관리하는 것입니다. 즉, 하나의 연결이 하나의 fd에 해당합니다. 주류 Linux 서버에서 지원되는 기본 FD 수는 1024입니다. 동시 연결 수가 많은 경우 FD 부족으로 인해 "너무 많은 파일 열기" 오류가 발생하여 새 연결 설정에 실패하기 쉽습니다. Linux 서버에서 지원하는 최대 핸들 수를 여러 번 늘리는 것이 좋습니다(서버의 메모리 양과 관련됨).
3. [권장] -XX:+HeapDumpOnOutOfMemoryError 매개변수를 JVM으로 설정하면 JVM이 OOM 시나리오가 발생할 때 덤프 정보를 출력할 수 있습니다.

 참고: OOM은 확률적으로 발생하며 심지어 몇 달에 한 번씩 정기적으로 발생합니다. 발생 시 현장 정보는 문제 해결에 매우 중요합니다.
4. [참고] 서버의 내부 리디렉션에는 전달을 사용하고, 외부 리디렉션 주소를 생성하려면 URL 어셈블리 도구 클래스를 사용하세요. 그렇지 않으면 일관성 없는 URL 유지 관리 및 잠재적인 보안 위험이 발생할 수 있습니다.

5. 보안 규정

1. [필수] 사용자에게 속한 페이지 또는 기능은 권한 제어 확인을 받아야 합니다. 참고: 이는 사용자가 다른 사람의 주문을 보거나 수정하는 등 수평적 권한 확인을 수행하지 않고 다른 사람의 데이터에 마음대로 접근하고 조작하는 것을 방지합니다.
2. [필수] 민감한 사용자 데이터를 직접 표시하는 것은 금지되며, 표시 데이터는 민감도를 낮추어야 합니다. 참고: 귀하의 개인 휴대폰 번호 조회 시, 개인정보 유출을 방지하기 위해 가운데 4자리를 가려 158****9119로 표시됩니다.
3. [필수] SQL 인젝션을 방지하고 스트링 스플라이싱 SQL이 데이터베이스에 접근하는 것을 방지하기 위해 사용자가 입력하는 SQL 매개변수는 매개변수 바인딩이나 METADATA 필드 값으로 엄격하게 제한되어야 합니다.
4. [필수] 사용자가 전달한 모든 매개변수의 유효성을 확인해야 합니다. 참고: 매개변수 확인을 무시하면 다음과 같은 결과가 발생할 수 있습니다.
litz 메모리 오버플로를 일으키는 과도한 페이지 크기
litz 느린 데이터베이스 쿼리를 유발하는 악의적인 명령
임의 리디렉션
litz SQL 주입
 역직렬화 주입
litz 일반 입력 소스 문자열 서비스 거부 ReDoS 설명: Java JavaJava 코드는 정규식을 사용하여 클라이언트의 입력을 확인합니다. 일부 정규식은 일반 사용자 입력을 확인하는 데 문제가 없습니다. 그러나 공격자가 확인을 위해 특수하게 구성된 문자열을 사용하는 경우 무한 루프가 발생할 수 있습니다.
5. [필수] 안전하게 필터링되지 않았거나 HTML 페이지로 올바르게 이스케이프되지 않은 사용자 데이터를 출력하는 것은 금지되어 있습니다.
6. [필수] 양식 및 AJAX 제출에 대해 CSRF 보안 필터링을 수행해야 합니다. 설명: CSRF(교차 사이트 요청 위조)는 일반적인 프로그래밍 취약점입니다. CSRF 취약점이 있는 애플리케이션/웹사이트의 경우, 공격자는 피해자 사용자가 URL에 액세스하자마자 사용자가 모르는 사이에 그에 따라 데이터베이스의 사용자 매개변수를 수정할 수 있습니다.
7. [필수] 문자 메시지, 이메일, 전화 통화, 주문, 결제 등 플랫폼 리소스를 사용할 때 수량 제한, 피로 제어, 인증 코드 확인 등 재생 방지 제한을 수정하여 구현해야 합니다. 남용 및 남용.

 참고: 등록 시 인증 코드가 휴대폰으로 전송되는 경우 개수와 빈도에 제한이 없으면 이 기능을 사용하여 다른 사용자를 괴롭히고 SMS 플랫폼 리소스를 낭비할 수 있습니다.

위 내용은 Java 코딩 사양 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.