Java 프로그래밍에서는 언어 사양 또는 표준 API 문서를 통해서만 일부 지식을 배울 수 없습니다. 이 기사에서는 가장 일반적으로 사용되는 관용구, 특히 추측하기 어려운 관용구를 수집하려고 노력할 것입니다.
이 기사의 모든 코드를 공공 장소에 넣었습니다. 자격 증명없이 선호도에 따라 코드 스 니펫을 복사하고 수정할 수 있습니다.
equals () 구현
클래스 사람 {문자열 이름; int 생일 세포; 바이트 [] RAW; public boolean equals (Object obj) {if (! obj instance) false를 반환합니다. 다른 사람 = (사람) obj; return name.equals (기타 .name) && 생일 year == Other.birthyear && arrays.equals (raw, other.raw); } public int hashcode () {...}} 매개 변수는 주변 클래스가 아닌 유형 객체 여야합니다.
foo.equals (null)는 false를 반환해야하며 NullPointerException을 던질 수 없습니다. (모든 클래스의 null 인스턴스는 항상 false를 반환하므로 위 코드를 실행할 수 있습니다.)
기본 유형 도메인의 비교 (예 : int)는 ==이며, 기본 유형 배열 도메인의 비교는 Arrays.equals ()에서 사용됩니다.
덮어 쓰기가 equals ()되면 hashcode ()를 덮어 쓰고 equals ()와 일치하도록하십시오.
참조 : java.lang.object.equals (객체).
hashcode () 구현
클래스 사람 {문자열 a; 대상 B; 바이트 C; int [] d; public int hashcode () {return a.hashcode () + b.hashcode () + c + arrays.hashcode (d); } public boolean Equals (Object O) {...}} x 및 y 객체에 x.equals (y) == true가 있으면 x.hashcode () == y.hashcode ()를 확인해야합니다.
역 제안에 따르면 x.hashcode ()! = y.hashcode ()이면 x.equals (y) == false는 참 이루야합니다.
x.equals (y) == false 일 때 x.hashcode ()! = y.hashcode ()를 보장 할 필요는 없습니다. 그러나 가능한 한 오래 할 수 있다면 해시 테이블의 성능을 향상시킵니다.
Hashcode ()의 가장 간단한 법적 구현은 단순히 0을 반환하는 것입니다. 이 구현이 정확하지만 해시 맵과 같은 데이터 구조가 매우 느리게 실행됩니다.
비교 () 구현
클래스 사람은 비슷한 <person> {string firstName; 문자열 마지막 이름; int 생일; // FirstName과 비교하고, 마지막 이름에 의한 타이를 break 다. 마지막으로 Birthdate Public int comporeto (person other) {if (firstname.compareto (기타 .firstname)! = 0) return firstname.compareto (기타 .firstname); else if (lastname.compareto (기타 .lastname)! = 0) return lastname.compareto (기타 .lastname); else if (birthdate <other.birthdate) return -1; else if (birthdate> other.birthdate) 반환 1; 그렇지 않으면 0; }} 원시 유형 대신 비교할 수있는 일반 버전을 항상 구현하십시오. 코드 볼륨을 절약하고 불필요한 번거 로움을 줄일 수 있기 때문입니다.
결과를 반환하는 표지판 (음수/제로/양수)에 관심이 있으면 크기가 중요하지 않습니다.
Comparator.compare () 구현은 이것과 유사합니다.
클론 구현 ()
클래스 값은 복제 가능한 {String ABC; 더블 푸; int [] 막대; 고용 된 날짜; 공개 값 clone () {try {value result = (value) super.clone (); result.bars = result.bars.clone (); result.hired = result.hired.clone (); 반환 결과; } catch (clonenotsupportedException e) {// 불가능한 새로운 AssertionError (e); }}} Super.clone ()을 사용하여 객체 클래스가 새 개체를 생성하는 책임을지게합니다.
기본 유형 도메인이 올바르게 복사되었습니다. 다시 말하지만, 우리는 String 및 Biginteger와 같은 불변의 유형을 복제 할 필요가 없습니다.
모든 비-프리맨티 유형 필드 (객체 및 배열)의 깊은 복사를 수동으로 수행합니다.
클로닝 가능한 클래스가 구현되며 Clone () 메소드는 ClonenOnsUpportedException을 던지지 않아야합니다. 따라서이 예외를 포착하여 무시하거나 확인되지 않은 예외로 마무리해야합니다.
Object.Clone () 메소드를 사용하지 않고 Clone () 메소드를 수동으로 구현하는 것은 괜찮고 합법적입니다.
StringBuilder 또는 StringBuffer를 사용하십시오
// join ([ "a", "b", "c") -> "a and b and c"string join (list <string> strs) {StringBuilder sb = new StringBuilder (); 부울 첫 번째 = 참; for (string s : strs) {if (first) first = false; else sb.append ( "and"); sb.append (들); } return sb.toString ();} 시간 효율이 O (n^2)이기 때문에 다음과 같은 중복 문자열 연결을 사용하지 마십시오.
StringBuilder 또는 StringBuffer를 사용할 때는 actubend () 메소드를 사용하여 텍스트를 추가하고 toString () 메소드를 사용하여 전체 텍스트를 연결할 수 있습니다.
StringBuilder가 더 빠르기 때문에 우선 순위가 부여됩니다. StringBuffer의 모든 방법은 동기화되며 일반적으로 동기화 된 방법이 필요하지 않습니다.
범위에서 임의의 정수를 생성합니다
random rand = new random (); // 1과 6 사이의 Diceroll () {return rand.nextint (6) + 1;}를 포함하여. 항상 Java API 메소드를 사용하여 정수 범위에서 난수를 생성하십시오.
결과가 편향되어 있기 때문에 이러한 불확실한 용도에 대해 math.abs (rand.nextint ()) %n을 사용하려고 시도하지 마십시오. 또한 rand.nextint () == integer.min_value와 같이 결과 값이 음수 일 수 있습니다.
iterator.remove () 사용
void filter (list <string> list) {for (iterator <string> iter = list.iterator (); iter.hasnext ();) {String item = iter.next (); if (...) iter.remove (); }}remove () 메소드는 최근에 반환 된 다음 () 메소드의 항목에 작용합니다. 각 항목은 remove () 메소드 만 한 번만 사용할 수 있습니다.
리턴 문자열
String Reverse (String s) {return new StringBuilder (s) .reverse (). toString ();}이 방법은 아마도 Java 표준 라이브러리에 추가되어야합니다.
스레드를 시작하십시오
다음 세 가지 예는 다른 방식으로 동일한 일을합니다.
런 가능성을 구현하는 방법 :
void startAthread0 () {new Thread (new myrunnable ()). start ();} 클래스 myrunnable empless runnable {public void run () {...}}스레드를 상속하는 방법 :
void startTheRread1 () {new Mythread (). start ();} 클래스 신화는 스레드 {public void Run () {...}}을 확장합니다.스레드를 익명으로 상속하는 방법 :
void startTheRread2 () {new Thread () {public void Run () {...}} .Start ();}run () 메소드를 직접 호출하지 마십시오. Thread.start () 메소드는 항상 호출되어 새 스레드를 생성하고 새로 생성 된 스레드가 run ()을 호출하게합니다.
Fintally를 사용하십시오
I/O 스트림 예 :
void writestuff ()는 ioexception {outputStream out = new FileOutputStream (...); {out.write (...); } 마침내 {out.close (); }}Lock example:
void dowithlock (잠금 잠금) {lock.acquire (); try {...} 마침내 {lock.release (); }} 시도 전 진술이 실행되지 않고 예외가 발생하면 최종 문자 블록이 실행되지 않습니다. 그러나이 예에서 무엇을 하든지 자원의 출시에 대해 걱정할 필요가 없습니다.
Try Statement 블록의 명령문이 예외를 던지면 프로그램의 실행은 최종 문장 블록으로 이동하여 가능한 많은 문장을 실행 한 다음이 메소드에서 벗어나지 않습니다 (이 메소드에 또 다른 주변 장치가 마지막 명령문 블록이없는 한).
입력 스트림에서 바이트 데이터를 읽습니다
inputStream in = (...); try {while (true) {int b = in.read (); if (b == -1) 파손; (... process b ...)}} 마침내 {in.close ();}read () 메소드는 스트림에서 읽은 다음 바이트 수를 반환하거나 (0 및 255를 포함하여 0 ~ 255) 스트림 끝에 도달하면 -1을 반환합니다.
입력 스트림에서 블록 데이터를 읽습니다
inputStream in = (...); try {byte [] buf = new Byte [100]; while (true) {int n = in.read (buf); if (n == -1) 파손; (... 오프셋이있는 Process buf = 0이고 길이 = n ...)} 마침내 {in.close ();}read () 메소드가 반드시 전체 BUF를 채우는 것은 아니므로 처리 로직에서 반환 길이를 고려해야합니다.
파일에서 텍스트를 읽으십시오
bufferedReader in = new bufferedReader (new inputStreamReader (new FileInputStream (...), "UTF-8"); try {while (true) {String line = in.readline (); if (line == null) break; (... 프로세스 라인 ...)}} 마침내 {in.close ();} BufferedReader 객체의 생성은 매우 장점으로 보입니다. Java는 바이트와 문자를 두 가지 다른 개념으로 취급하기 때문입니다 (이것은 C와 다릅니다).
소켓과 같은 FileInputStream 대신 모든 유형의 입력 스트림을 사용할 수 있습니다.
bufferedReader.Readline () 스트림 끝에 도달하면 NULL을 반환합니다.
한 번에 하나의 문자를 읽으려면 reader.read () 메소드를 사용하십시오.
UTF-8없이 다른 문자 인코딩을 사용할 수 있지만 그렇게하지 않는 것이 좋습니다.
파일에 텍스트를 작성하십시오
printwriter out = new printwriter (new OutputStreamWriter (새 파일 OutputStream (...), "UTF-8"); try {out.print ( "Hello"); out.print (42); out.println ( "World!");} 마침내 {out.close ();} 프린트 라이터 객체의 생성은 매우 장점으로 보입니다. Java는 바이트와 문자를 두 가지 다른 개념으로 취급하기 때문입니다 (이것은 C와 다릅니다).
System.out와 마찬가지로 print () 및 println ()을 사용하여 여러 유형의 값을 인쇄 할 수 있습니다.
UTF-8없이 다른 문자 인코딩을 사용할 수 있지만 그렇게하지 않는 것이 좋습니다.
방어 점검 가치
int factorial (int n) {if (n <0) 새로운 불법 불법 행위 ( "정의되지 않은"); else if (n> = 13) 새로운 arithmeticexception을 던지십시오 ( "결과 오버플로"); 그렇지 않으면 (n == 0) 반환 1; 그렇지 않으면 n * factorial (n -1);} 반환 입력 값이 이러한 조건을 명시 적으로 감지 할 수있는 입력 값이 양수이고 충분히 작다고 생각하지 마십시오.
잘 설계된 함수는 가능한 모든 입력 값에 대해 올바르게 실행할 수 있어야합니다. 모든 상황이 고려되고 잘못된 출력이 없는지 확인하십시오 (예 : 오버플로).
예방 테스트 대상
int findIndex (list <string> 목록, 문자열 대상) {if (list == null || target == null) 던지기 새 nullPointerException (); ...}그 객체 매개 변수는 무효가 아니라고 생각하지 마십시오. 이 조건을 명시 적으로 감지합니다.
예방 감지 어레이 인덱스
void frob (byte [] b, int index) {if (b == null) 새 nullpointerexception () 던지기; if (index <0 || index> = b.length) 새 IndexOfBoundSexection (); ...}주어진 배열 인덱스가 경계를 가로 지르지 않을 것이라고 생각하지 마십시오. 명시 적으로 감지합니다.
예방 감지 어레이 간격
void frob (byte [] b, int off, int len) {if (b == null) 새 nullpointerexception (); if (off <0 || off> b.length || len <0 || b.length -off <len) 새 indexoutofboundsexception (); ...}주어진 배열 간격 (예 : OFF에서 시작하여 LEN 요소를 읽는 것)은 한계를 넘어서지 않을 것이라고 생각하지 마십시오. 명시 적으로 감지합니다.
배열 요소를 채우십시오
루프 사용 :
// 배열의 각 요소를 123Byte [] a = (...)로 채 웁니다.
(우선) 표준 라이브러리 사용 방법 :
배열 .fill (a, (바이트) 123);
배열 요소를 범위로 복사하십시오
루프 사용 :
// 오프셋에서 시작하는 'a'에서 시작하는 'A'에서 8 개의 요소를 복사합니다. // 오프셋 6에서 시작하는 // 'b'로 시작합니다. // 'a'및 'b'가 별개의 ArraysByte [] a = (...); byte [] b = (...); for (int i = 0; i <8; i ++) b [6 + i] = a [3 + i];
(우선) 표준 라이브러리 사용 방법 :
System.arraycopy (a, 3, b, 6, 8);
배열 크기를 조정하십시오
루프 사용 (스케일링) :
// 'a'a 'a'a = (...); byte [] b = new byte [newlen]; for (int i = 0; i <a.length; i ++) // A의 길이로 올라갑니다. b [i] = a [i]; a = b;
루프 사용 (크기 감소) :
// array 'a'a newlenbyte [] a = (...); byte [] b = new byte [newlen]; for (int i = 0; i <b.length; i ++) // b b [i] = a [i]; a = b;
(우선) 표준 라이브러리 사용 방법 :
a = arrays.copyof (a, newlen);
4 바이트를 int에 포장합니다
int packbigendian (byte [] b) {return (b [0] & 0xff) << 24 | (b [1] & 0xff) << 16 | (B [2] & 0xff) << 8 | (b [3] & 0xff) << 0;} int packlittleendian (byte [] b) {return (b [0] & 0xff) << 0 | (b [1] & 0xff) << 8 | (B [2] & 0xff) << 16 | (B [3] & 0xff) << 24;}int를 4 바이트로 분해하십시오
바이트 [] unpackbigendian (int x) {return new byte [] {(byte) (x >>> 24), (byte) (x >>> 16), (byte) (x >>> 8), (byte) (x >>> 0)}; (바이트) (x >>> 8), (byte) (x >>> 16), (byte) (x >>> 24)};}서명되지 않은 오른쪽 편이 연산자 (>>>)를 항상 사용하여 비트를 감싸고 산술 오른쪽 시프트 연산자 (>>)를 사용하지 마십시오.