머리말
2016 년 3 월에 개정하고 내 자신의 작업과 일상 학습 경험을 기반으로 코드를 최적화 해야하는 이유를 다시 방문했습니다. 수정하기 전에 내 진술은 다음과 같습니다.
새우를 먹는 고래와 마찬가지로, 아마도 한두 마리의 새우를 먹는 것은 고래에게는 효과적이지 않지만, 새우를 너무 많이 먹으면 고래가 자연스럽게 가득 차게됩니다. 코드 최적화는 동일합니다. 아마도 하나 또는 두 개의 최적화는 코드의 실행 효율성을 향상시키는 데 거의 의미가 없지만 모든 곳에서 코드 최적화에주의를 기울일 수있는 한 일반적으로 코드의 실행 효율성을 향상시키는 데 매우 유용합니다.
이 견해는 현재 관점에서 코드 최적화의 이유이지만 완전히 정확하지는 않습니다. 오늘날 기계 기술이 개발되면서 서버에는 8 개의 코어, 16 개의 코어 및 64 비트 CPU가 있으며 코드 실행 효율은 매우 높습니다. StringBuilder는 StringBuffer를 대체하고 ArrayList는 벡터를 대체하여 Minuscule에 의해 코드 작동 효율성을 향상시킵니다. 프로젝트의 모든 시점을 발견하더라도 코드 작업의 명백한 변경 사항을 볼 수는 없습니다.
코드 최적화의 가장 중요한 역할은 다음과 같습니다. 알려지지 않은 오류를 피하는 것입니다. 온라인으로 실행되는 코드 중에는 온라인 환경과 개발 환경이 매우 다르고 오류 포지셔닝이 종종 작은 이유이기 때문에 많은 예상치 못한 오류가 발생합니다. 그러나이 오류를 해결하려면 먼저 자체 검증을 한 다음 교체 할 클래스 파일을 패키지하고 비즈니스를 중단하고 다시 시작해야합니다. 성숙한 프로젝트의 경우 실제로 마지막 프로젝트는 실제로 큰 영향을 미치 므로이 기간 동안 사용자가 응용 프로그램에 액세스 할 수 없습니다. 따라서 코드를 작성할 때 소스의 다양한 세부 사항에주의를 기울이고, 최상의 선택 및 최상의 선택을 사용하면 알 수없는 오류를 크게 피하고 장기적으로 작업량을 크게 줄입니다.
코드 최적화의 목표는 다음과 같습니다.
1. 코드의 볼륨을 줄입니다
2. 코드 작동의 효율성을 향상시킵니다
이 기사의 일부 내용 중 일부는 인터넷에서 나오고 일부는 매일 일과 공부에서 나옵니다. 물론 이것은 중요하지 않습니다. 중요한 것은 이러한 코드 최적화의 세부 사항이 정말로 유용한 지 여부입니다. 이 기사는 오랫동안 업데이트됩니다. 공유 할 가치가있는 코드 최적화 세부 사항을 만나는 한이 기사는 때때로 업데이트됩니다.
코드 최적화 세부 사항
(1) 클래스의 최종 수정 자와 가능한 한 많은 방법을 지정하십시오.
최종 수정자가있는 클래스는 파생되지 않습니다. Java Core API에는 java.lang.string과 같은 최종 적용의 많은 예가 있으며 전체 클래스는 최종입니다. 클래스의 최종 수정자를 지정하면 클래스가 상속되는 것을 방지 할 수 있으며, 메소드의 최종 수정자를 지정하면 메소드가 재정의되지 않을 수 있습니다. 클래스가 최종으로 지정되면 해당 클래스의 모든 방법은 최종입니다. Java 컴파일러는 모든 최종 방법을 인화 할 수있는 기회를 찾습니다. 인라인은 Java의 달리기 효율성을 향상시키는 데 큰 의미가 있습니다. 자세한 내용은 Java 런타임 최적화를 참조하십시오. 이 움직임은 평균 50%증가한 성능을 향상시킬 수 있습니다.
(2) 개체를 재사용하려고 노력하십시오
특히 문자열 객체를 사용하기 위해 문자열 연결이 발생할 때 StringBuilder/StringBuffer를 사용해야합니다. Java Virtual Machines는 객체를 생성하는 데 시간을 소비해야 할뿐만 아니라 향후 이러한 객체를 수집하고 처리하는 데 쓰레기를 소비해야 할 수도 있으므로 너무 많은 객체를 생성하면 프로그램의 성능에 큰 영향을 미칩니다.
(3) 가능한 한 로컬 변수를 사용하십시오
메소드를 호출 할 때 전달 된 매개 변수와 통화에서 생성 된 임시 변수는 스택에 저장되며 더 빠릅니다. 정적 변수, 인스턴스 변수 등과 같은 다른 변수는 모두 힙에 생성되며 느린 힙에 생성됩니다. 또한 스택에서 생성 된 변수가 완료되면 이러한 내용이 사라지고 추가 쓰레기 수집이 필요하지 않습니다.
(4) 시간이 지남에 따라 흐름을 닫습니다
Java 프로그래밍 중에 데이터베이스 연결 및 I/O 스트리밍 작업을 수행 할 때주의하십시오. 사용 후 시간을 닫아 리소스를 릴리스하십시오. 이러한 큰 물체의 작동은 큰 시스템 오버 헤드를 유발하고 조심하지 않으면 심각한 결과를 초래할 것입니다.
(5) 변수의 반복 계산을 최소화합니다
개념을 명확히하기 위해, 메소드에 한 문장이 하나만 있더라도 스택 프레임 생성, 메소드를 호출 할 때 사이트 보호 및 메소드를 호출 할 때 사이트를 복원하는 등 여전히 소비됩니다. 예를 들어 다음 작업은 다음과 같습니다.
for (int i = 0; i <list.size (); i ++) {...}이를 대체하는 것이 좋습니다.
for (int i = 0, length = list.size (); i <length; i ++) {...}이런 식으로 List.Size ()가 매우 커지면 많은 소비가 줄어 듭니다.
(6) 게으른 적재 전략을 채택하려고 노력하십시오. 즉, 필요할 때 창조하십시오.
예를 들어:
String str = "aaa"; if (i == 1) {list.add (str);}이를 대체하는 것이 좋습니다.
if (i == 1) {String str = "aaa"; list.add (str);}(7)주의해서 이상을 사용하십시오
이상은 성능에 좋지 않습니다. 예외를 던지려면 먼저 새 개체를 만들어야합니다. Throwable 인터페이스의 생성자는 Fillinstacktrace ()라는 로컬 동기화 방법을 호출합니다. FillInstackTrace () 메소드는 스택을 확인하고 통화 추적 정보를 수집합니다. 예외가 발생하는 한, Java 가상 머신은 처리 중에 새 개체가 생성되므로 통화 스택을 조정해야합니다. 예외는 오류 처리에만 사용될 수 있으며 프로그램 흐름을 제어하는 데 사용해서는 안됩니다.
(8) 시도하지 마십시오. 캐치 ... 루프에서 가장 바깥 쪽 층에 배치해야합니다.
네티즌이 제시 한 의견에 따르면, 나는 이것이 논의 할 가치가 있다고 생각합니다.
(9) 추가 할 컨텐츠 길이를 추정 할 수있는 경우, 기본 레이어의 배열에서 구현 된 수집 및 공구 클래스의 초기 길이를 지정하십시오.
예를 들어, ArrayList, LinkedLlist, StringBuilder, StringBuffer, Hashmap, Hashset 등. StringBuilder를 예로 들어보십시오.
StringBuilder () // 기본값 16 자 공간 문자 문자 문자업 builder (int size) // 기본적으로 16 자 공간 문자 문자 stringbuilder (string str) 할당 // 기본값 할당 16 자 + str.length () 문자 공간
초기화 용량은 클래스의 생성자를 통해 설정할 수 있으며 (여기서는 위의 StringBuilder를 참조 할뿐만 아니라 성능을 크게 향상시킬 수 있습니다. 예를 들어, StringBuilder, 길이는 현재 StringBuilder가 유지할 수있는 문자 수를 나타냅니다. StringBuilder가 최대 용량에 도달하면 자체 용량을 2 배로 증가시키고 2를 추가 할 수 있습니다. StringBuilder가 최대 용량에 도달 할 때마다 새 문자 배열을 생성하고 이전 문자 배열 컨텐츠를 새 문자 배열에 복사해야합니다. 이것은 매우 성능이 높은 작업입니다. 길이를 지정하지 않고 5000 문자가 문자 배열에 저장되어 있다고 추정 할 수 있다면 5000에 가장 가까운 2의 전력은 4096이며, 각 확장에 추가 된 2는 2에 관계없이 다음과 같습니다.
4096을 기준으로 8194 크기의 문자 배열을 적용하여 최대 12290 크기의 문자 배열이 한 번에 추가됩니다. 처음에 5000 크기의 문자 배열을 지정할 수 있다면 원래 4096자를 새로운 문자 배열에 복사 할 수있는 공간의 두 배 이상을 절약 할 수 있습니다.
이것은 메모리 공간을 낭비 할뿐만 아니라 코드 작동 효율성을 줄입니다. 따라서 기본 배열에서 구현 된 컬렉션 및 도구 클래스에 대한 합리적인 초기화 용량을 설정하는 것은 잘못된 것이 아니므로 즉각적인 결과를 가져올 것입니다. 그러나 배열 + 링크 된 목록에서 구현 된 해시 맵과 같은 컬렉션은 초기 크기를 예상 크기와 동일하게 설정해서는 안됩니다. 테이블에 연결된 하나의 객체 만 거의 0이기 때문에 초기 크기를 N 전원 2로 설정하는 것이 좋습니다. 2,000 개의 요소가있는 경우 New HashMap (128) 및 New Hashmap (256)으로 설정할 수 있습니다.
(10) 많은 양의 데이터를 복사 할 때 System.ArrayCopy () 명령을 사용하십시오.
(11) 곱셈 및 분할 사용 시프트 작업
예를 들어:
for (val = 0; val <100000; val += 5) {a = val * 8; b = val / 2;}시프트 작업을 사용하면 컴퓨터 하단에서 포지셔닝 작업이 가장 편리하고 빠르기 때문에 성능을 크게 향상시킬 수 있으므로 다음으로 수정하는 것이 좋습니다.
for (val = 0; val <100000; val += 5) {a = val << 3; b = val >> 1;}시프트 조작이 빠르지 만 코드를 이해하기 어려울 수 있으므로 해당 주석을 추가하는 것이 가장 좋습니다.
(12) 루프에서 지속적으로 객체 참조를 만들지 마십시오.
예를 들어:
for (int i = 1; i <= count; i ++) {object obj = new Object (); }이 접근법은 Count Object Object Reference가 메모리에 존재하게합니다. 카운트가 크면 메모리를 소비합니다. 다음으로 변경하는 것이 좋습니다.
Object obj = null; for (int i = 0; i <= count; i ++) {obj = new Object ();}이런 식으로 메모리에는 객체 객체 참조가 하나뿐입니다. 새 개체 ()가 사용될 때마다 객체 객체 참조는 다른 객체를 가리키지 만 메모리에는 하나의 객체 만 있으므로 메모리 공간이 크게 저장됩니다.
(13) 효율 및 유형 검사의 고려에 따라 배열을 가능한 한 많이 사용해야합니다. 배열 크기를 결정할 수없는 경우에만 배열리스트를 사용해야합니다.
(14) Hashmap, Arraylist 및 StringBuilder를 사용하십시오. 스레드 안전이 필요하지 않으면 해시 가능, 벡터 및 StringBuffer를 사용하는 것이 좋습니다. 후자의 3 개는 동기화 메커니즘을 사용하여 성능 오버 헤드를 가지고 있습니다.
(15) 배열을 공개 정적 결승으로 선언하지 마십시오
이것은 의미가 없기 때문에 참조를 정적 최종으로 정의하고 배열의 내용은 여전히 마음대로 변경 될 수 있습니다. 배열을 공개로 선언하는 것은 보안 취약점이므로 외부 클래스에서 배열을 변경할 수 있음을 의미합니다.
(16) 적절한 경우에 단일 케이스를 사용하십시오
싱글 톤을 사용하면로드 부담을 줄이고 로딩 시간을 단축하며 로딩 효율을 향상시킬 수 있지만 모든 장소가 싱글 톤에 적합한 것은 아닙니다. 간단히 말해서, 싱글 톤은 주로 다음 세 가지 측면에 적용됩니다.
자원 사용을 제어하고, 스레드 동기화를 통해 자원의 동시 액세스 제어 인스턴스 생성을 제어하여 데이터 공유를 제어하기위한 리소스를 저장하는 목적을 달성하고, 직접 연관성을 설정하지 않고 다중 관련없는 프로세스 또는 스레드 간의 통신을 가능하게합니다.
(17) 마음대로 정적 변수를 사용하지 않도록 노력하십시오
객체가 정적으로 정의 된 변수에 의해 참조 될 때 GC는 일반적으로 다음과 같은 객체가 차지하는 힙 메모리를 재활용하지 않습니다.
공개 클래스 A {private static b b = new b (); }이 시점에서 정적 변수 B의 수명주기는 클래스 A와 동일합니다. 클래스 A가 제거되지 않으면 참조 B로 가리키는 B 객체는 프로그램이 종료 될 때까지 메모리에 상주합니다.
(18) 더 이상 필요한 세션을 시간에 정리하십시오
더 이상 활성화되지 않은 세션을 지우려면 많은 응용 프로그램 서버에는 기본 세션 타임 아웃 (일반적으로 30 분)이 있습니다. 애플리케이션 서버가 더 많은 세션을 저장 해야하는 경우 메모리가 충분하지 않은 경우 운영 체제는 데이터의 일부를 디스크로 전송합니다. Application Server는 MRU (최근에 가장 자주 사용되는) 알고리즘에 따라 일부 비활성 세션을 디스크에 버릴 수 있으며 메모리 예외가 충분하지 않을 수도 있습니다. 세션이 디스크에 버려 지려면 먼저 직렬화해야합니다. 대규모 클러스터에서는 직렬화 객체가 비싸다. 따라서 세션이 더 이상 필요하지 않은 경우 httpsession의 invalidate () 메소드를 제 시간에 호출하여 세션을 지워야합니다.
(19) ArrayList와 같이 RandomAccess 인터페이스를 구현하는 컬렉션은 Foreach Loop to Traverse 대신 가장 일반적인 루프를 사용해야합니다.
JDK는 사용자에게 권장합니다. RandomAccess 인터페이스에 대한 JDK API의 설명은 다음과 같습니다. RandomAccess 인터페이스 구현은 빠른 랜덤 액세스를 지원하는 것을 나타내는 데 사용됩니다. 이 인터페이스의 주요 목적은 일반 알고리즘이 동작을 변경하여 무작위 또는 연속 액세스 목록에 적용될 때 우수한 성능을 제공 할 수 있도록하는 것입니다. 실제 경험에 따르면 RandomAccess 인터페이스를 구현하는 클래스 인스턴스에 무작위로 액세스하는 경우 루프에 일반을 사용하는 효율이 Foreach 루프를 사용하는 것보다 높습니다. 반대로, 순차적으로 액세스하면 반복기를 사용하는 것이 더 효율적입니다. 다음과 유사한 코드를 사용하여 판단 할 수 있습니다.
if (randomAccess) {for (int i = 0; i <list.size (); i ++) {}} else {iterator <?> iterator = list.eritable (); while (iterator.hasnext ()) {iterator.next ()}}Foreach Loop의 기본 구현 원리는 반복자이며 Java Syntax Sugar 1 : 가변 길이 매개 변수 및 Foreach 루프 원리를 참조하십시오. 따라서 문장의 후반부는 "반대로, 순차적으로 액세스하면 반복을 사용하는 경우 더 효율적일 것"이라는 것은 순차적으로 액세스하는 클래스 인스턴스가 Foreach 루프를 사용하여 순차적으로 통과 함을 의미합니다.
(20) 동기화 방법 대신 동기 코드 블록을 사용하십시오
이것은 이미 다중 스레드 모듈의 기사 동기화 된 잠금 메소드 블록에 명확하게 언급되어 있습니다. 전체 메소드를 동기화해야한다는 것을 결정할 수 없다면 동기화 된 코드 블록을 사용하여 동기화 할 필요가없는 코드를 동기화하지 않아 코드 실행 효율에 영향을 미칩니다.
(21) 상수를 정적 최종으로 선언하고 자본으로 이름을 지정하십시오.
이런 식으로, 이러한 내용은 컴파일 동안 일정한 풀에 넣을 수 있으며, 런타임 동안 생성 된 상수 값의 계산을 피할 수 있습니다. 또한 자본에서 상수 이름의 이름을 지정하면 상수와 변수의 차이를 촉진 할 수 있습니다.
(22) 사용하지 않은 개체를 만들지 말고 사용하지 않은 클래스를 가져 오지 마십시오.
이것은 말이되지 않습니다. "로컬 변수 I의 값이 사용되지 않는 경우"및 "import java.util이 사용되지 않는다"는 코드에 나타나면 이러한 쓸모없는 내용을 삭제하십시오.
(23) 프로그램 작동 중 반사 사용을 피하십시오
자세한 내용은 반사를 참조하십시오. 반사는 Java가 사용자에게 제공하는 매우 강력한 기능입니다. 강력한 기능은 종종 낮은 효율성을 의미합니다. 프로그램 작동 중에 반사 메커니즘, 특히 메소드의 호출 메소드를 자주 사용하는 것이 좋습니다. 실제로 필요한 경우, 암시적인 접근 방식은 반사를 통해 객체를 인스턴스화하고 프로젝트가 시작될 때 메모리에 넣는 것입니다. 사용자는 피어와 상호 작용할 때 가장 빠른 응답 속도에만 관심이 있으며 피어 프로젝트가 시작되는 데 얼마나 걸리는지 신경 쓰지 않습니다.
(24) 데이터베이스 연결 풀과 스레드 풀을 사용하십시오
두 풀은 물체를 재사용하는 데 사용되며, 전자는 연결을 자주 개방하고 닫는 것을 피하고 후자는 자주 생성과 실의 파괴를 피합니다.
(25) IO 작업에 버퍼 입력 및 출력 스트림 사용
버퍼 입력 및 출력 스트림, 즉 BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream, IO 효율성을 크게 향상시킬 수 있습니다.
(26)보다 순차적 인 삽입 및 임의의 액세스가있는 장면에 ArrayList를 사용하고 더 많은 요소 삭제 및 중간 삽입이있는 장면에 LinkedList를 사용하십시오.
이것은 ArrayList 및 LinkedList의 원리를 이해함으로써 알려져 있습니다.
(27) 공개 방법에서 너무 많은 공식 매개 변수를 허용하지 마십시오.
공개 방법은 외부 세계에 제공되는 방법입니다. 이러한 방법을 너무 많은 공식 매개 변수를 제공하면 두 가지 주요 단점이 있습니다.
객체 지향 프로그래밍 아이디어 위반. Java는 모든 것이 대상이라는 것을 강조합니다. 너무 많은 공식 매개 변수이며 객체 지향 프로그래밍 아이디어와 일치하지 않습니다. 너무 많은 매개 변수는 필연적으로 메소드 호출의 오류 확률을 증가시킵니다.
예를 들어, "너무 많은"가 3 또는 4를 참조하는 수는 jdbc를 사용하여 insertstudentinfo 메소드를 작성합니다. 학생 테이블에 10 개의 학생 정보 필드가 있습니다. 이 10 개의 매개 변수는 엔티티 클래스에서 삽입 메소드의 공식 매개 변수로 캡슐화 될 수 있습니다.
(28) 문자열 변수와 문자열 상수가 동등한 경우 문자열 상수 앞에 기록됩니다.
다음 코드가 있다면 이것은 비교적 일반적인 속임수입니다.
String str = "123"; if (str.equals ( "123")) {...}다음으로 수정하는 것이 좋습니다.
String str = "123"; if ( "123".equals (str)) {...}이것은 주로 널 포인터 예외를 피할 수 있습니다
(29) Java에는 if (i == 1)과 if (1 == i) 사이에 차이가 없지만 읽기 습관의 관점에서 전자를 사용하는 것이 좋습니다.
때때로 사람들은 "if (i == 1)"과 "if (1 == i)"사이에 차이가 있는지 묻습니다. 이것은 C/C ++로 시작합니다.
C/C ++에서 "if (i == 1)"판단 조건은 유효하며 0 및 비 0을 기준으로합니다. 0은 거짓을 의미하고 0이 아닌 것은 사실을 의미합니다. 그러한 코드가있는 경우 :
int i = 2; if (i == 1) {...} else {...}C/C ++는 "i == 1"이 유효하지 않다고 판단하므로 0으로 표시됩니다. 하지만 if :
int i = 2; if (i = 1) {...} else {...}프로그래머가 실수로 "if (i == 1)"을 "if (i = 1)"로 씁니다. 문제가 발생합니다. if 내에서 1에 I를 할당하십시오. 내용이 0이 아니라고 판단하면 반환 된 사실이지만, 분명히 2이고 비교 값은 1이고, 반환 해야하는 거짓입니다. 이 상황은 C/C ++의 개발에서 발생할 가능성이 높으며 이해하기 어려운 오류를 유발할 것입니다. 따라서 IF 문의 개발자의 잘못된 할당 작업을 피하기 위해 if 문을 다음과 같이 작성하는 것이 좋습니다.
int i = 2; if (1 == i) {...} else {...}이런 식으로 개발자가 실수로 "1 = i"를 쓴하더라도 C/C ++ 컴파일러는 변수 값 i를 1에 할당 할 수 있지만 일정한 값 1을 i에 할당 할 수 없기 때문에 가능한 빨리 확인할 수 있습니다.
그러나 Java에서는 "if (i = 1)"C/C ++의 구문이 나타날 수 없습니다.이 구문이 작성되면 Java는 "유형 불일치 : int에서 부울로 변환 할 수 없다"는 오류를 컴파일하고보고합니다. 그러나 Java에서 "if (i == 1)"과 "if (1 == i)"사이에는 의미 론적 차이가 없지만 읽기 습관 측면에서 전자를 사용하는 것이 좋습니다.
(30) 배열에서 toString () 메소드를 사용하지 마십시오.
어레이에 toString ()을 사용하여 인쇄 된 내용을 살펴 보겠습니다.
int i = 2; if (1 == i) {...} else {...}나가기 :
i@18a992f
원래 의도는 배열의 내용을 인쇄하는 것이지만 배열 참조가 널이므로 널 포인터 예외를 유발할 수 있습니다. 그러나 배열 toString ()에게는 의미가 없지만 컬렉션의 내용은 컬렉션의 상위 클래스가 컬렉션의 상위 클래스 인 객체의 toString () 메소드를 다시 작성하기 때문에 인쇄 할 수 있습니다.
(31) 범위를 벗어난 기본 데이터 유형에 대한 하향 힘 변환을 만들지 마십시오.
이것은 원하는 결과를 얻지 못할 것입니다.
public static void main (String [] args) {long l = 12345678901234L; int i = (int) l; System.out.println (i);}우리는 그들 중 일부를 얻을 것으로 기대할 수 있지만 결과는 다음과 같습니다.
1942892530
설명하십시오. Java는 64 비트의 8 바이트이므로 컴퓨터에서 12345678901234의 표현은 다음과 같습니다.
0000 0000 0000 0000 0000 1011 001111011111111001110 0010 1111 1111 0010
int 유형 데이터는 4 바이트와 32 비트입니다. 위의 이진 데이터의 처음 32 비트는 낮은 비트에서 가져옵니다.
0111 0011 1111110 0010 1111 1111 0010
이 바이너리 스트링은 10 진수 1942892530으로 표시되므로 위의 콘솔의 컨텐츠 출력입니다. 이 예에서 두 가지 결론을 도출 할 수 있습니다.
1. 정수 유형의 기본 데이터 유형은 int, long l = 12345678901234L입니다. 이 숫자는 int의 범위를 초과하므로 마지막에는 L이 있으며, 이는 이것이 긴 유형 숫자임을 나타냅니다. 그건 그렇고, 플로팅 포인트 유형의 기본 유형은 두 배이므로 플로트를 정의 할 때 ""float f = 3.5f "로 작성해야합니다.
2. 다음으로, 또 다른 문장을 씁니다. "int ii = l + i;" Long + Int가 길고 int에 할당 할 수 없기 때문에 오류를보고합니다.
(32) 공개 컬렉션 클래스에서 사용되지 않은 데이터는 제 시간에 제거해야합니다.
컬렉션 클래스가 공개 인 경우 (즉, 메소드의 속성이 아닙니다),이 컬렉션의 요소는 항상 참조를 가리키는 참조가 있기 때문에 자동으로 릴리스되지 않습니다. 따라서 공개 컬렉션의 특정 데이터가 사용되지 않고 제거되지 않으면 공개 컬렉션이 계속 증가하여 시스템이 메모리 누출 가능성을 갖게됩니다.
(33) 기본 데이터 유형을 문자열로 변환합니다. 기본 데이터 유형 .toString ()은 가장 빠른 방법이며 String.Valueof (data) 및 data +""가 가장 느린 방법입니다.
일반적으로 기본 데이터 유형을 변환하는 세 가지 방법이 있습니다. 정수 유형 데이터 (예 : tostring (), String.valueof (i) 및 i+""세 가지 방법이 있습니다. 세 가지 방법은 얼마나 효율적입니까? 테스트보기 :
public static void main (String [] args) {int looptime = 50000; 정수 i = 0; Long StartTime = System.CurrentTimeMillis (); for (int j = 0; } system.out.println ( "String.valueof () :" + (System.CurrentTimeMillis () -StartTime) + "MS"); STARTTIME = SYSTEM.CURRENTTIMEMILLIS (); for (int j = 0; } system.out.println ( "integer.toString () :" + (System.CurrentTimeMillis () -StartTime) + "MS"); STARTTIME = SYSTEM.CURRENTTIMEMILLIS (); for (int j = 0; j <looptime; j ++) {String str = i+""; } system.out.println ( "i + /" /":" + (System.currentTimeMillis () -StartTime) + "MS");}실행 결과는 다음과 같습니다.
String.valueof () : 11msinteger.tostring () : 5ms + "": 25ms
따라서 기본 데이터 유형을 향후 문자열로 변환하면 toString () 메소드를 사용하는 데 우선 순위를 부여해야합니다. 이유에 관해서는 매우 간단합니다.
String.valueOf() 메소드를 Integer.toString() 메소드라고하지만 호출하기 전에 Integer.toString() 메소드를 판단하는 것은 짧습니다. I + "" "하단 계층은 StringBuilder 구현을 사용합니다. 먼저 Append Method를 사용하여 스 플라이싱 한 다음 Tostring () 메소드를 사용하여 문자열을 얻습니다.
세 가지와 비교할 때, 그것은 분명히 가장 빠르고, 가장 빠르며, 가장 느린 것입니다.
(34) 가장 효율적인 방법을 사용하여지도를 가로 지르십시오.
지도를 가로 지르는 방법에는 여러 가지가 있습니다. 일반적으로지도에서 키와 가치를 가로 지르는 데 필요한 것. 권장되고 가장 효율적인 방법은 다음과 같습니다.
public static void main (String [] args) {Hashmap <String, String> hm = new Hashmap <String, String> (); hm.put ( "111", "222"); <map.entry <string, string >> entryset = hm.entryset (); iterator <map.entry <string, string >> iter = actoretset.iterator (); while (iter.hasnext ()) {map.entry <string, String> entry = iter.next (); System.out.println (entry.getKey () + "/t" + entery.getValue ()); }} 이 맵의 키 값을 반복하려면 " Set<String> keySet = hm.keySet();" 사용하는 것이 더 적절합니다.
(35) Close ()의 자원을 위해 별도로 운영하는 것이 좋습니다.
예를 들어, 다음과 같은 코드가 있습니다.
try {xxx.close (); yyy.close ();} catch (예외 e) {...}다음으로 수정하는 것이 좋습니다.
try {xxx.close ();} catch (예외 e) {... ...} try {yyy.close ();} catch (예외 e) {... ...}약간 번거로움이지만 자원 누출을 피할 수 있습니다. 수정 된 코드가 없으면 xxx.close ()가 예외를 던지면 캐치 블록에 들어갑니다. yyy.close ()는 실행되지 않으며 YYY 리소스는 재활용되지 않으며 항상 점유됩니다. 이와 같은 더 많은 코드를 사용하면 리소스 핸들이 유출 될 수 있습니다. 다음 글쓰기 방법으로 변경 한 후에는 XXX와 YYY가 무엇이든 관계없이 닫히게됩니다.
(36) ThreadLocal의 경우 사용 전후를 제거해야합니다.
현재 기본적으로 모든 프로젝트는 스레드 풀링 기술을 사용합니다. 스레드 수와 재사용 스레드를 동적으로 구성 할 수 있습니다.
그러나 프로젝트에서 ThreadLocal을 사용하는 경우 사용 전후를 제거하십시오. 위에서 언급 한 스레드 풀 기술은 스레드를 재사용하는 것이기 때문에 코드가 실행되는 동안 스레드가 파괴되지 않고 다음 사용을 기다릴 것입니다. ThreadLocal.threadlocalMap을 고정하는 스레드 클래스의 참조를 살펴 보겠습니다.
/*이 스레드와 관련된 ThreadLocal 값. 이지도는 strooklocal 클래스에 의해 유지됩니다. */threadLocal.threadlocalmap rdulelocals = null;
스레드가 파괴되지 않으면 이전 스레드 세트의 ThreadLocal.threadLocalMap의 데이터가 여전히 존재 함을 의미합니다. 다음 스레드 가이 스레드를 재사용하면 원하는 내용이 원하는 컨텐츠가 아닌 이전 스레드 세트의 데이터 일 가능성이 높습니다.
이 문제는 매우 모호합니다. 이 원인으로 인한 오류가 발생하면 관련 경험이나 견고한 기초 없이이 문제를 찾기가 매우 어렵습니다. 따라서 코드를 작성할 때 이에주의를 기울여야하므로 후속 작업량이 줄어 듭니다.
(37) 악마 번호를 끊임없는 정의로 바꾸는 것을 잊지 마십시오. 악마 수의 존재는 코드의 가독성을 크게 줄입니다. 문자열 상수가 상수 정의를 사용하는지 여부가 상황에 따라 다를 수 있습니다.
(38) 긴 또는 길이의 초기 할당이 소문자 L 대신 대문자 L을 사용하면 문자 L이 숫자 1과 혼동하기가 매우 쉽기 때문에이 점은 매우 상세하며 주목할 가치가 있습니다.
(39) 모든 재 작성 방법은 @override 주석을 유지해야합니다
이 작업을 수행하는 세 가지 이유가 있습니다.
(1)이 방법이 부모 클래스에서 상속 된 것은 분명합니다.
(2) getObject () 및 get0bject () 메소드. 전자의 네 번째 편지는 "O"이고, 후자의 네 번째 부모와 자녀는 "0"입니다. @override 주석을 추가하면 다시 쓰기가 성공했는지 즉시 결정할 수 있습니다.
(3) 추상 클래스에서 메소드 서명을 수정하면 구현 클래스가 즉시 컴파일 오류를보고합니다.
(40) JDK7에서 새로 도입 된 객체 도구 클래스를 사용하여 객체와 직접 a.equals (b)를 비교하는 것이 좋습니다.
(41) 루프 본체의 문자열에 "+"를 사용하지 말고 StringBuilder를 사용하여 지속적으로 추가하십시오.
문자열 스 플라이 싱에 "+"를 사용하지 않는 이유에 대해 이야기하겠습니다. 메소드가있는 경우 :
public String actendstr (String grist, string ... appendstrs) {if (부록 == null || appendstrs.length == 0) {return oristr; } for (문자열 부록 : 부록) {oristr += 부록; } return gistr;}이 코드를 컴파일 한 후 javap -c를 사용하여 .class 파일을 디 컴파일하여 핵심 부분을 가로 채립니다.
이는 가상 머신이 "+"연산자가 문자열을 스플릿으로 접을 때마다 문자열을 연결 한 다음 StringBuilder를 새롭게 한 다음 Append 메소드를 호출 한 다음 마지막으로 문자열을 Oristring () 메소드를 호출하여 문자열을 Oristring 객체로 변환한다는 것을 의미합니다. 즉, 루프가 새로운 stringbuilder ()를 몇 번이나 기억 낭비하는 것입니다.
(42) runtimeexception에서 상속 된 Java 클래스 라이브러리에 정의 된 런타임 예외 클래스를 캡처하지 마십시오.
예외 처리 효율은 낮으며, 대부분의 런타임 예외 클래스는 다음과 같은 프로그래머가 완전히 피할 수 있습니다.
(43) 여러 스레드에서 임의의 인스턴스를 사용하지 마십시오. 인스턴스를 공유하는 것은 스레드 안전이지만 동일한 시드에 대한 경쟁으로 인해 성능 저하가 발생합니다. JDK7 후에는 ThreadLocalRandom을 사용하여 랜덤 번호를 얻을 수 있습니다.
동일한 종자에 대한 경쟁이 성능 저하를 일으키는 이유를 설명하십시오. 예를 들어, 랜덤 클래스의 nextInt () 메소드 구현을 살펴보십시오.
public int nextint () {return next (32); }다음 (int bits) 메소드가 호출되는데,이 방법은 보호 된 방법입니다.
보호 된 int next (int bits) {Long Oldseed, Nextseed; Atomiclong Seed = this.seed; do {OldSeed = seed.get (); NextSeed = (OldSeed * multiplier + addend) & 마스크; } while (! seed.compareAndset (OldSeed, NextSeed)); return (int) (NextSeed >>> (48- 비트));}그리고 여기의 씨앗은 글로벌 변수입니다.
/***이 유사 숫자 생성기와 관련된 내부 상태. * (이 클래스의 방법에 대한 사양은이 값의 진행중인 컴퓨팅을 설명합니다.) */ Private Final Atomiclong Seed;
여러 스레드가 동시에 임의의 숫자를 얻으면 동일한 시드와 경쟁하여 효율이 감소합니다.
(44) 정적 클래스, 싱글 톤 클래스 및 공장 수업은 생성자를 비공개로 설정했습니다.
이것은 우리가 밖에서 새로운 것을 새롭게 할 필요가 없기 때문입니다. 생성자를 비공개로 설정 한 후 이러한 클래스가 인스턴스 객체를 생성하지 않도록합니다.
추신
우수한 코드는 모든 작은 최적화에서 나옵니다. 모든 세부 사항에주의를 기울이면 프로그램의 실행 효율성을 향상시킬뿐만 아니라 알려지지 않은 많은 문제를 피할 수 있습니다.
위는 편집자가 도입 한 44 개의 Java 코드 최적화 제안입니다. 나는 그것이 당신에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!