6 주차 - 8 장메서드, 9 장일반적인프로그래밍원칙 - 종현, 고운 8 장메서드 아이템 49. 매개변수가유효한지검사하라 핵심정리 메서드몸체가시작되기전에매개변수를검사해야한다. 미리확인한다면즉각적이고깔끔한방식으로예외를던질수있다 매개변수검사를제대로하

Similar documents
PowerPoint Presentation

JAVA PROGRAMMING 실습 08.다형성

PowerPoint Presentation

PowerPoint Presentation

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

PowerPoint Presentation

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

07 자바의 다양한 클래스.key

PowerPoint Presentation

gnu-lee-oop-kor-lec06-3-chap7

PowerPoint 프레젠테이션

JAVA PROGRAMMING 실습 09. 예외처리

PowerPoint Presentation

gnu-lee-oop-kor-lec11-1-chap15

Cluster management software

슬라이드 1

Microsoft PowerPoint - Java7.pptx

교육자료

쉽게 풀어쓴 C 프로그래밍

슬라이드 1

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

JVM 메모리구조

C# Programming Guide - Types

JAVA PROGRAMMING 실습 05. 객체의 활용

Microsoft PowerPoint - CSharp-10-예외처리

PowerPoint Presentation

Design Issues

PowerPoint Presentation

q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2

쉽게 풀어쓴 C 프로그래밍

금오공대 컴퓨터공학전공 강의자료

쉽게

PowerPoint 프레젠테이션

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

슬라이드 1

예외 예외정의예외발생예외처리예외전파 단정 단정의선언 단정조건검사옵션 2

No Slide Title

PowerPoint 프레젠테이션

JUNIT 실습및발표

슬라이드 1

제11장 프로세스와 쓰레드

(8) getpi() 함수는정적함수이므로 main() 에서호출할수있다. (9) class Circle private double radius; static final double PI= ; // PI 이름으로 로초기화된정적상수 public

Microsoft PowerPoint - ch07 - 포인터 pm0415

(Microsoft PowerPoint - java1-lecture11.ppt [\310\243\310\257 \270\360\265\345])

PowerPoint 프레젠테이션

Microsoft PowerPoint - 04-UDP Programming.ppt

Microsoft PowerPoint - Lect04.pptx

설계란 무엇인가?

Microsoft PowerPoint - additional01.ppt [호환 모드]

Microsoft PowerPoint - lec2.ppt

Java ...

9장.예외와 단정

Microsoft PowerPoint - C++ 5 .pptx

PowerPoint Template

PowerPoint Presentation

Spring Boot/JDBC JdbcTemplate/CRUD 예제

Microsoft PowerPoint - 2강

PowerPoint Presentation

JAVA PROGRAMMING 실습 02. 표준 입출력

쉽게 풀어쓴 C 프로그래밍

슬라이드 1

12-file.key

10.0pt1height.7depth.3width±â10.0pt1height.7depth.3widthÃÊ10.0pt1height.7depth.3widthÅë10.0pt1height.7depth.3width°è10.0pt1height.7depth.3widthÇÁ10.0pt1height.7depth.3width·Î10.0pt1height.7depth.3width±×10.0pt1height.7depth.3width·¡10.0pt1height.7depth.3width¹Ö pt1height.7depth.3widthŬ10.0pt1height.7depth.3width·¡10.0pt1height.7depth.3width½º, 10.0pt1height.7depth.3width°´10.0pt1height.7depth.3widthü, 10.0pt1height.7depth.3widthº¯10.0pt1height.7depth.3width¼ö, 10.0pt1height.7depth.3width¸Þ10.0pt1height.7depth.3width¼Ò10.0pt1height.7depth.3widthµå

Microsoft PowerPoint - chap01-C언어개요.pptx

ilist.add(new Integer(1))과 같이 사용하지 않고 ilist.add(1)과 같이 사용한 것은 자바 5.0에 추가된 기본 자료형과 해당 객체 자료 형과의 오토박싱/언박싱 기능을 사용한 것으로 오토박싱이란 자바 컴파일러가 객체를 요구하는 곳에 기본 자료형

Microsoft PowerPoint - Lect07.pptx

PowerPoint Presentation

11장 포인터

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

쉽게 풀어쓴 C 프로그래밍

TEST BANK & SOLUTION

Microsoft PowerPoint - chap06-2pointer.ppt

Microsoft PowerPoint - Introduction to Google Guava.pptx

슬라이드 1

17장 클래스와 메소드

ThisJava ..

Microsoft PowerPoint - chap06-1Array.ppt

목차 INDEX JSON? - JSON 개요 - JSONObject - JSONArray 서울시공공데이터 API 살펴보기 - 요청인자살펴보기 - Result Code - 출력값 HttpClient - HttpHelper 클래스작성 - JSONParser 클래스작성 공공

Microsoft PowerPoint - chap10-함수의활용.pptx

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

JAVA PROGRAMMING 실습 02. 표준 입출력

1. 객체의생성과대입 int 형변수 : 선언과동시에초기화하는방법 (C++) int a = 3; int a(3); // 기본타입역시클래스와같이처리가능 객체의생성 ( 복습 ) class CPoint private : int x, y; public : CPoint(int a

PowerPoint Presentation

파일로입출력하기II - 파일출력클래스중에는데이터를일정한형태로출력하는기능을가지고있다. - PrintWriter와 PrintStream을사용해서원하는형태로출력할수있다. - PrintStream은구버전으로가능하면 PrintWriter 클래스를사용한다. PrintWriter

Visual Basic 반복문

Microsoft PowerPoint - java1-lab5-ImageProcessorTestOOP.pptx

Microsoft PowerPoint - lec12 [호환 모드]

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

PowerPoint Presentation

설계란 무엇인가?

예제 2) Test.java class A intvar= 10; void method() class B extends A intvar= 20; 1"); void method() 2"); void method1() public class Test 3"); args) A

Microsoft PowerPoint - Chap12-OOP.ppt

A Tour of Java V

슬라이드 1

학습목표 함수프로시저, 서브프로시저의의미를안다. 매개변수전달방식을학습한다. 함수를이용한프로그래밍한다. 2

PowerPoint Template

Transcription:

6 주차 - 8 장메서드, 9 장일반적인프로그래밍원칙 - 종현, 고운 8 장메서드 아이템 49. 매개변수가유효한지검사하라 핵심정리 1. 2. 메서드몸체가시작되기전에매개변수를검사해야한다. 미리확인한다면즉각적이고깔끔한방식으로예외를던질수있다. 49-1. 매개변수검사를제대로하지않았을문제점 메서드가수행되는중간에모호한예외를던지며실패할수있다. 메서드는잘수행됐지만잘못된결과를반환할수있다. 메서드에포함된객체를이상한상태로만들어놔서미래의알수없는시점에메서드와관련없는오류를발생시킬수있다. 49-2. 자바 7 에추가된 java.util.objects.requirenonnull 메서드를사용하라 가장문제가자주발생하는건 null 에대한처리인데.. requirenonnull 을이용하면입력값을그대로반환하므로값을사용하는동시에 null 검사를수행할수있다. this.strategy = Objects.requireNonNull(strategy, ""); java.util.objects.requirenonnull public static <T> T requirenonnull(t obj, String message) { if (obj == null){ throw new NullPointerException(message); return obj; 49-3. 자바 9 부터는 java.util.objects 에범위기능이더해졌다 checkfromindexsize(int fromindex, int size, int length) fromindex( 포함 ) 에서 fromindex+ size( 전용 ) 까지의하위범위가 0( 포함 ) 부터 length( 전용 ) 까지의범위내에있는지점검한다. checkfromtoindex(int fromindex, int toindex, int length) fromindex( 포함 ) 에서 toindex( 포함 ) 까지의하위범위가 0( 포함 ) 부터 length( 포함 ) 까지의범위내에있는지점검한다. checkindex(int index, int length) index 가 0( 포함 ) 부터 length( 포함 ) 범위의범위내에있는지점검한다. 49-4. public 이아닌메서드는단언문 (assert) 를사용해유효성을검증한다 자신이단언한조건이무조건참이어야한다. 실패하면 AssertionError 를던진다. 성능저하가없다.

private static void sort(long a[], int offset, int length) { assert a!= null; assert offset >= 0 && offset <= a.length; assert length >= 0 && length <= a.length-offset;... // 단언문은특별한에러를나타내지는않지만 vm 옵션을주면에러를배터낸다. java [ -enableassertions -ea ] [:<package name>"..." :<class name> ] AssertionError Exception in thread "main" java.lang.assertionerror at com.github.sejoung.codetest.methods.parametersvalidity.main(parametersvalidity.java:10) Process finished with exit code 1 49-5. 단예외적으로, 유효성검사비용이지나치게높거나실용적이지않을때, 혹은계산과정에서암묵적으로수행될때는생략한다. 리스트안의객체들은모두상호비교되기때문에, 정렬과정에서체크한다. Collections.sort(List); 아이템 50. 적시에방어적복사본을만들라 핵심정리 1. 2. 클래스가클라이언트로부터받거나반환하는구성요소가가변이라면그요소는반드시방어적으로복사해야한다. 복사비용이너무크거나그요소를잘못수정할일이없음을신뢰한다면방어적복사를수행하지않을수도있다. 단, 해당구성요소를수정했을때의책임이클라이언트에있음을문서에명시하도록하자. 50.1 불변식을적용하여방어적으로프로그래밍을한다 기간을표시하는클래스

public final class Period { private final Date start; private final Date end; /** * @param start * @param end.. * @throws IllegalArgumentException. * @throws NullPointerException start end null. */ public Period(Date start, Date end) { if (start.compareto(end) > 0) throw new IllegalArgumentException( start + " " + end + "."); this.start = start; this.end = end; public Date start() { return start; public Date end() { return end; @Override public String tostring() { return start() + " " + end(); Period 인스턴스의내부를공격해보자 public class Attacks { public static void main(string[] args) { Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); end.setyear(78); System.out.println(p.end()); //!! p end. 50-2. Date 는가변이고, 낡은 API 이니새로운코드를작성할때는아래코드로대체한다 JAVA 8 이후등장한불변객체인 Instant, LocalDateTime, ZonedDateTime 지원

Instant instant = Instant.now(); System.out.println("Current instant = "+ instant); LocalDateTime localdatetime = LocalDateTime.now(); System.out.println("Current localdatetime = "+ localdatetime); ZonedDateTime zoneddatetime = ZonedDateTime.now(); System.out.println("Current zoneddatetime = "+ zoneddatetime); ///---------- ------------------------------ Current instant = 2019-04-08T14:09:26.186598Z Current localdatetime = 2019-04-08T23:09:26.226079 Current zoneddatetime = 2019-04-08T23:09:26.226459+09:00[Asia/Seoul] //---------------------------------------------- 하지만, Date 처럼가변인낡은값타입을사용하던시절이워낙길었던탓에여전히많은곳에서 Date 를사용하고있다. 50-3. 생성자에서받은가변매개변수각각을방어적으로복사한다 매개변수의유효성검사전에방어적복사본을만들고, 이복사본으로유효성검사한점에주목하자. 멀티쓰레딩환경에서는순간의찰나에다른쓰레드가원본객체를수정할위험이있기때문이다. public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareto(this.end) > 0) throw new IllegalArgumentException(this.start + " " + this.end + "."); public Date start() { return start; public Date end() { return end; 하지만접근자메서드를통해 Period 인스턴스를다시공격할수있다 Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); p.end().setyear(78); // p! 수정한접근자 - 필드의방어적복사본을반환한다

public Date start() { return new Date(start.getTime()); public Date end() { return new Date(end.getTime()); 완벽한불변으로거듭나다 50-4. 방어적복사에는성능저하가따르고, 또항상쓸수있는것도아니다. 호출자가컴포넌트내부를수정하지않으리라확신하면방어적복사를생략할수도있다. 하지만이런상황에서도호출자에게해당매개변수나반환값을수정하지말아야함을명확히문서화하는게좋다 아이템 51. 메서드시그니처를신중히설계하라 51-1. 매서드이름을신중히짖자 표준명명규칙을따라야한다. ( 아이템 68) 긴이름은피하자. 자바라이브러리의 API 가이드를참조하라. 51-2. 편의메서드를너무많이만들지말자 메서드가너무많은클래스는익히고, 사용하고, 문서화하고, 테스트하고, 유지보수하기어렵다. 확신이서지않으면만들지말자. 51-3. 매개변수목록은짧게유지하자 4 개이하가좋다. 같은타입의매개변수가여러개가연달아나오는경우매우안좋다. 51-4. 매개변수의타입으로는클래스보다인터페이스가더낫다 Map 을예로들어 HashMap, TreeMap, ConcurrentHashMap, TreeMap 등. 어떤 Map 구현체도인수로건넬수있다. 51-5. boolean 보다는원소 2 개짜리열거타입이낫다 열거타입을사용하면코드를읽고쓰기가더쉬워진다. public enum TemperatureScale { FAHRENHEIT, CELSIUS ; // Thermometer.newInstance(true); Thermometer.newInstance(TemperatureScale.CELSIUS); //. 아이템 52. 다중정의는신중히사용하라 핵심정리 1. 2. 일반적으로매개변수수가같을때는다중정의를피하는게좋다. 상황에따라매개변수수가같을때사용해야한다면, 넘겨주는매개변수를형변환하여정확한다중정의메서드를선택되도록해야한다. 52-1. 재정의 (override) 한메서드는동적으로선택되고, 다중정의 (overloading) 한메서드는정적으로선택된다.

예제 1. 컬렉션분류기 - 이프로그램은무엇을출력할까? public class CollectionClassifier { // (overloading) public static String classify(set<?> s) { return ""; public static String classify(list<?> lst) { return ""; public static String classify(collection<?> c) { return " "; public static void main(string[] args) { Collection<?>[] collections = { new HashSet<String>(), new ArrayList<BigInteger>(), new HashMap<String, String>().values() ; for (Collection<?> c : collections) System.out.println(classify(c)); //////////////////////////////// //////////////////////////////// Process finished with exit code 0 main문을실행하면집합 - 리스트 - 그외순서로출력될것같지만실제로는 그외 만세번출력된다. 다중정의 (overloading) 된메소드 (classify) 중어떤것을호출할지는컴파일타임에정해진다. 컴파일타임에는 for문안의 c는항상 Collection<?> 타입이다. 그래서런타임시에타입이계속바뀌어도영향을못준다. 예제2. 재정의 (override) 메서드

class Wine { String name() { return ""; class SparklingWine extends Wine { @Override String name() { return " "; class Champagne extends SparklingWine { @Override String name() { return ""; public class Overriding { public static void main(string[] args) { List<Wine> winelist = List.of( new Wine(), new SparklingWine(), new Champagne()); for (Wine wine : winelist) System.out.println(wine.name()); //////////////////////////////// //////////////////////////////// Process finished with exit code 0 재정의 (Overrode) 된메소드는런타임타입이어떤메서드를호출할지기준이된다. 예제 3. 예제 1 의해결방안

// instanceof public class FixedCollectionClassifier { public static String classify(collection<?> c) { return c instanceof Set? "" : c instanceof List? "" : " "; public static void main(string[] args) { Collection<?>[] collections = { new HashSet<String>(), new ArrayList<BigInteger>(), new HashMap<String, String>().values() ; for (Collection<?> c : collections) System.out.println(classify(c)); /////////////////////////////////// //////////////////////////////// Process finished with exit code 0 52-2. 안전하고보수적으로가려면매개변수수가같은다중정의는만들지말자 다중정의하는대신메서드이름을다르게지어주는방법을사용하자 ObjectOutputStream 클래스 writeboolean(boolean); writeint(int); writelong(long); // read. readboolean(); readint(); readlong(); 52-3. 단, 매개변수가근본적으로다르면, 매개변수수가같은다중정의메서드를생성해도괜찮다 근본적으로다르다는건두타입의 (null 이아닌 ) 값을서로어느쪽으로든형변환할수없다는뜻이다. 52-4. 오토박싱으로인한다중정의메서드의취약점

public class SetList { public static void main(string[] args) { Set<Integer> set = new TreeSet<>(); List<Integer> list = new ArrayList<>(); for (int i = -3; i < 3; i++) { set.add(i); list.add(i); // set = [-3, -2, -1, 0, 1, 2] // list = [-3, -2, -1, 0, 1, 2] for (int i = 0; i < 3; i++) { set.remove(i); list.remove(i); // // set = [-3, -2, -1] // list = [-3, -2, -1] System.out.println(set + " " + list); //////////////////////// /////////////////////////////////// [-3, -2, -1] [-2, 0, 2] Process finished with exit code 0 SET LIST remove(object o); - 동일한값을삭제 remove(int index); - 지정한위치를삭제 remove(object o); - 동일한값을삭제 for (int i = 0; i < 3; i++) { set.remove(i); list.remove((integer) i); //////////////////////// /////////////////////////////////// [-3, -2, -1] [-3, -2, -1] Process finished with exit code 0 52-5. 람다와메소드참조도다중정의에혼란을이르켰다

// 1. Thread new Thread(System.out::println).start(); // 2. ExecutorService submit ExecutorService es = Executors.newCachedThreadPool(); es.submit(system.out::println); 2 번은실패한다. 원인은바로 es.submit() 이다중정의되어있기때문이다. 또한 println() 도다중정의되어있기때문에, 다중정의해소알고리즘이우리의기대처럼동작하지않는다. 메서드를다중정의할때, 서로다른함수형인터페이스라도같은위치의인수로받아서는안된다. 아이템 53. 가변인수는신중히사용하라 핵심정리 1. 2. 인수개수가일정하지않은매서드를정의해야한다면가변인수가반드시필요하다. 메서드를정의할때필수매개변수를가변인수앞에두고, 가변인수를사용할때는성능문제까지고려하자 53-1. 가변인수메서드는명시한타입의인수를 0 개이상받을수있다 입력받은 int 인수들의합을계산해주는가변인수메서드 static int sum(int... args) { int sum = 0; for (int arg : args) sum += arg; return sum; ///////////////////////////////////////////////////// int result = sum(1,2); // 2 int result = sum(); // 0 53-2. 위코드의문제점발생 1 필수인수가 1개이상이어야할경우문제가된다. 인수를 1 개이상받도록유효성검사추가한메서드 // static int min(int... args) { if (args.length == 0) throw new IllegalArgumentException(" 1."); int min = args[0]; for (int i = 1; i < args.length; i++) if (args[i] < min) min = args[i]; return min;

53-3. 문제점발생 2 인수를 0개로넣으면, ( 컴파일타임이아닌 ) 런타임에실패한다 0 개로넣으면컴파일시점에오류를알려주도록변경한메서드 static int min(int firstarg, int... remainingargs) { int min = firstarg; for (int arg : remainingargs) if (arg < min) min = arg; return min; ///////////////////////////////////////////////////// int result = sum(); //!!! 53-4. 가변인수를사용한유용한기능들 // printf System.out.printf("%s, %s, %d", "Korea", "good", 10); // (?) // 65 53-5. 성능에민감한상황이라면가변인수가걸림돌이될수있다 예를들어해당메서드호출의 95% 가인수를 3 개이하로사용한다고가정하자. public void foo() { public void foo(int a1) { public void foo(int a1, int a2) { public void foo(int a1, int a2, int a3) { public void foo(int a1, int a2, int a3, int... rest) { // 5% // EnumSet.of(). public static <E extends Enum<E>> EnumSet<E> of(e e) {; public static <E extends Enum<E>> EnumSet<E> of(e e1, E e2) {; public static <E extends Enum<E>> EnumSet<E> of(e e1, E e2, E e3) {; public static <E extends Enum<E>> EnumSet<E> of(e e1, E e2, E e3, E e4) {; public static <E extends Enum<E>> EnumSet<E> of(e e1, E e2, E e3, E e4, E e5) {; public static <E extends Enum<E>> EnumSet<E> of(e first, E... rest) {; 아이템 54. null이아닌, 빈컬렉션이나배열을반환하라핵심정리 1. null이아닌, 빈배열이나컬렉션을반환하라. null을반환하는 API는사용하기어렵고, 오류처리코드도늘어나고성능도좋지않다. 54-1. null 을반환하는나쁜예제

private final List<Cheese> cheesesinstock =...; public List<Cheese> getcheeses() { return cheesesinstock.isempty()? null : new ArrayList<>(cheesesInStock); //////////////////////////////////////////////////////////// // null, null. List<Cheese> cheeses = shop.getcheeses(); if(cheeses!= null && cheeses.contains(cheese.stilton)) System.out.println(",."); 54-2. 빈컬렉션을반환하는올바른예 (1) 빈컬렉션과배열은굳이새로할당하지않고도반환할수있다. public List<Cheese> getcheeses() { return new ArrayList<>(cheesesInStock); 54-3. 빈컬렉션을반환하는올바른예 (2) 성능고려 가능성은작지만, 사용패턴에따라빈컬렉션할당이성능을눈에띄게떨어뜨릴수도있다. 해결방법은매번똑같은 불변 컬렉션을반환하는것이다. // Collections emptylist, emptymap, emptyset. public List<Cheese> getcheeses() { return cheesesinstock.isempty()? Collections.emptyList() : new ArrayList<>(cheesesInStock); 54-4. 배열을쓸때도, null 대신길이가 0 인배열을반환하라 // 0 public List<Cheese> getcheeses() { return cheesesinstock.toarray(new Cheese[0]); ///////////////////////////////////////////////////////////////// // 0. private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0]; public List<Cheese> getcheeses() { return cheesesinstock.toarray(empty_cheese_array); ///////////////////////////////////////////////////////////////// //.

아이템 55. 옵셔널반환은신중히하라 핵심정리 1. 2. 3. 값을반환하지못할가능성이있고, 호출할때마다반환값이없을가능성을염두에둬야하는메서드라면옵셔널을반환해야할상황일수있다. 하지만옵셔널반환에는성능저하가뒤따르니, 성능에민감한메서드라면 null 을반환하거나예외를던지는편이나을수있다. 옵셔널을반환값이외의용도로쓰는경우는매우드물다. 자바 8 전에는메서드가특정조건에서값을반환할수없을때취할수있는선택지가두가지있었다. 예외를던지거나, Null 을반환하는것이다. 자바 8 이등장하면서 Optional 이라는또하나의선택지가추가되었다. 55-1. Optional 이란? Optional 이란, 값이있을수도있고없을수도있는객체이다. 참조타입의객체를한번감싼일종의래퍼클래스이다. Optional 은원소를최대 1 개가질수있는불변 Collection 이다. 자바 8 이전의코드보다 null-safe 한로직을처리할수있게해준다. Optional 을반환하여좀더로직을유연하게작성할수있게해준다. 55-2. Optional 메서드 1. Optional.empty() 2. 3. 내부값이비어있는 Optional 객체반환 Optional.of(T value) 내부값이 value 인 Optional 객체반환만약 value 가 null 인경우 NullPointerException 발생 Optional.ofNullable(T value) 4. T get() 가장자주쓰이는 Optional 생성방법 value 가 null 이면, empty Optional 을반환하고, 값이있으면 Optional.of 로생성 5. 6. 7. 8. 9. 10. 11. 12. 13. Optional 내의값을반환만약 Optional 내부값이 null 인경우 NoSuchElementException 발생 boolean ispresent() Optional 내부값이 null 이면 false, 있으면 true Optional 내부에서만사용해야하는메서드라고생각 boolean isempty() Optional 내부의값이 null 이면 true, 있으면 false ispresent() 메서드의반대되는메서드 void ifpresent(consumer<? super T> consumer) Optional 내부의값이있는경우 consumer 함수를실행 Optional filter(predicate predicate) Optional 에 filter 조건을걸어조건에맞을때만 Optional 내부값이있음조건이맞지않으면 Optional.empty 를리턴 Optional map(funtion<? super T,? extends U> f) Optional 내부의값을 Function 을통해가공 T orelse(t other)optional 내부의값이있는경우그값을반환 Optional 내부의값이 null 인경우 other 을반환 T orelseget(supplier<? extends T> supplier) Optional 내부의값이있는경우그값을반환 Optional 내부의값이 null 인경우 supplier 을실행한값을반환 T orelsethrow() Optional 내부의값이있는경우그값을반환 Optional 내부의값이 null 인경우 NoSuchElementException 발생 T orelsethrow(supplier<? extends X> exceptionsupplier) 55-3. Java8 이전의코드 Optional 내부의값이있는경우그값을반환 Optional 내부의값이 null 인경우 exceptionsupplier 을실행하여 Exception 발생

public class School { private ClassRoom classroom; public class ClassRoom { private Teacher teacher; private List<Student> students; public class Teacher { private Subject subject; private String name; public class Subject { private String subjectname; 이학교의교실의선생님의과목을반환하는코드를작성하면 school.getclassroom().getteacher().getsubject().getsubjectname(); 위와같은코드를작성할수있는데, 위와같은코드는전혀 null-safe 하지않은코드가된다. 그렇게 null 처리를추가해보면.. if(school!= null) { ClassRoom classroom = school.getclassroom(); if(classroom!= null) { Teacher teacher = classroom.getteacher(); if(teacher!= null) { Subject subject = teacher.getsubject(); if(subject!= null) { String subjectname = subject.getsubjectname(); return subjectname; return null; 조금보기좋게다듬으면아래와같다

if(school == null) { return null; ClassRoom classroom = school.getclassroom(); if(classroom == null) { return null; Teacher teacher = classroom.getteacher(); if(teacher == null) { return null; Subject subject = teacher.getsubject(); if(subject == null) { return null; return subject.getsubjectname(); 이정도로바꿀수있겠지만, 만족스러운코드는아니다. 55-4. Optional 을이용한코드 Optional.ofNullable(school).map(School::getClassRoom) //Optional<School>.map(ClassRoom::getTeacher) //Optional<ClassRoom>.map(Teacher::getSubject) //Optional<Teacher>.map(Subject::getSubjectName) //Optional<Subject>.orElse(null); 55-5. Optional 을활용한반환예제 Optional 을반환하여 client 에서더욱더유연하게로직을작성할수있다. Optional.of 에 null 을넣으면 NullPointerException 이발생하니주의해야한다. Optional 을리턴하는메서드에서는 null 을리턴해서는안된다. (Optional 의취지와맞지않기때문 )

// Effective Java public static <E extends Comparable<E>> Optional<E> max(collection<e> c) { if(c.isempty()) { return Optional.empty(); E result = null; for(e e : c) { if(result == null e.compareto(result) > 0) { result = Objects.requiredNonNull(e); return Optional.of(result); /////////////////////. ////////////////// // max() List<String> public static Optional<String> max(list<string> c) { if(c.isempty()) { // throw new IllegalArgumentException(" "); return Optional.empty(); String result = null; for(string e : c) { if(result == null e.compareto(result) > 0) { result = Objects.requiredNonNull(e); return Optional.of(result); // List<String> list = new ArrayList<String>(); list.add(""); list.add(""); list.add(""); Optional op = max(list); // Optional. // case 1 -. String name = op.orelse(""); System.out.println(name); // // case 2 -. String name = op.orelsethrow(exception::new); System.out.println(name); // // case 3 -. if(op.isempty()){ System.out.println("- list."); else{ System.out.println(op.get()); //. 55-6. Optional 안티패턴

Collection, Stream, 배열, 옵셔널같은컨테이너타입은 Optional 로감싸지말자 Optional 을 Map 의키나값으로사용하지말자 ispresent() 는아주신중히사용하거나다른메서드로대체하자. //. if(school.ispresent()) { Optional<ClassRoom> classroom = school.getclassroom(); if(classroom.ispresent()) { Optional<Teacher> teacher = classroom.getteacher(); if(teacher.ispresent()) { Optional<Subject> subject = teacher.getsubject(); if(subject.ispresent()) { String subjectname = subject.getsubjectname(); return subjectname; return null; 아이템 56. 공개된 API 요소에는항상문서화주석을작성하라 핵심정리 1. 2. 3. 4. 문서화주석은 API 를문서화하는가장훌륭하고효과적인방법이다. 공개 API 라면빠짐없이설명을달아야한다. 표준규약을일관되게지키자. 문서화주석이외에 HTML 태그를사용할수있다. 56-1. 모든공개된리소스에주석을달아야한다 API 를올바로문서화하려면공개된클래스, 인터페이스, 메서드, 필드선언에문서화주석을달아야한다. 직렬화할수있는클래스라면직렬화형태에대해서도적어야한다. 문서화주석이없다면 JavaDoc 도그저공개 API 요소들의선언만나열해주는게전부다. 문서가잘갖춰지지않은 API 는쓰기헷갈려서오류의원인이되기쉽다. 기본생성자에는문서화주석을달방법이없으니공개클래스는절대기본생성자를사용하면안된다. 유지보수까지고려한다면대다수의공개되지않은클래스, 인터페이스, 생성자, 메서드, 필드에도문서화주석을달아야한다. 56-2. 메서드용문서화주석에는규약을명료하게기술해야한다. 메서드가어떻게동작하는지를적는게아니라무엇을하는지기술해야한다. 클라이언트가해당메서드를호출하기위한 ** 전제조건 (precondition)** 을모두나열해야한다. 메서드가성공적으로수행된후에만족해야하는 ** 사후조건 (postcondition)** 도모두나열해야한다. 일반적으로전제조건은 @throw 태그로비검사예외를선언하여암시적으로기술한다. 비검사예외하나가전제조건하나와연결되는것이다. @param 태그를이용해그조건에영향받는매개변수에기술할수도있다. 56-3. 전제조건과사후조건뿐만아니라부작용도문서화하라 부작용이란사후조건으로명확히나타나지는않지만시스템의상태에따라어떠한변화를가져오는것을의미예를들어메서드에서백그라운드스레드를실행시키는메서드라면그사실을문서에밝혀야한다. 56-4. 문서화태그 태그 @throws 설명 발생가능성이있는모든예외에대해명시 @param 메서드의파라미터에대한정보. 매개변수가뜻하는값을명사구로쓴다. {@code 감싼내용을코드용폰트로렌더링한다. 또 HTML 요소나다른자바독태그를무시하고문자열로보여준다. @implspec 자기사용패턴 (self-use pattern) 에대해서도문서에남겨다른프로그래머에게그메서드를올바르게재정의하는방법을알려야한다. {@literal 이태그는 <, > 와같은 HTML 태그를무시하게해준다. @code 와비슷하지만, 코드폰트로렌더링하지는않는다. @summary Java 10 부터는 {@summary 라는요약설명전용태그가추가되어한번에사용가능하다. @index @index 태그를사용해 API 에서중요한용어를추가로색인화할수있다.

/** *. * * <p> <i></i>. *. * * @param index ; 0 * @return * @throws IndexOutOfBoundsException index, *, ({@code index < 0 index >= this.size()) */ E get(int index) { return null; 문서화주석에 HTML 태그 (<p> 와 <i>) 를쓴점에주목하자. 자바독유틸리티는문서화주석을 HTML 로변환한다. {@code 태그는감싼내용을코드용폰트로렌더링한다. 또 HTML 요소나다른자바독태그를무시하고문자열로보여준다. <pre>{@code</pre> 형태로여러줄로된코드예시를넣을수도있다. 56-5. 제네릭타입이나제네릭메서드의주석 제네릭타입이나제네릭메서드를문서화할때는모든타입매개변수에주석을달아야한다. /* *,. *, 1. * * @param <K> * @param <V> */ public interface Map<K, V> { 56-6. 열거타입에는상수별로주석을달아라 열거타입을문서화할때는상수들에도주석을달아야한다. 열거타입자체와열거타입의 public 메서드도물론이다.

/** *. */ public enum OrchestraSection { /**,,. */ WOODWIND, /**,. */ BRASS, /**,. */ PERCUSSION, /**,. */ STRING; 56-7. 애너테이션타입을문서화할때는멤버에도주석을달아라 애너테이션타입을문서화할때는멤버들에도모두주석을달아야한다. 애너테이션타입자체도물론이다. 필드설명은명사구로한다. 애너테이션타입의요약설명은프로그램요소에이애너테이션을단다는것이어떤의미인지를설명하는동사구로한다. /** * *. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExceptionTest { /** *. * (.) */ Class<? extends Throwable> value(); 9 장일반적인프로그래밍원칙 아이템 57. 지역변수의범위를최소화하라 1. 지역변수의유효범위를최소로줄여라. 유지보수성이높아지고오류가능성은낮아짐. 미리선언해두고쓸경우가독성도떨어지고, 실제변수사용시점엔타입과초깃값이기억나지않을수도있다.» 지역변수의범위를줄이는가장강력한기법 : ' 가장처음쓰일때선언하기 ' 2. 거의모든지역변수는선언과동시에초기화하라. 초기화에필요한정보가충분하지않다면선언을미뤄야한다. 예외 : try-catch 문변수값을 try 블록바깥에서도사용하는경우.

3. 반복문 향상된 for 문 > for 문 > while 문순으로사용추천 ( 버그방지 ) 예외발견이어려운 while 문 Iterator<Element> I = c.iterator(); while(i.hasnext()){ dosomething(i.next()); Iterator<Element> i2 = c2.iterator(); while(i.hasnext()){ dosomething(i2.next()); //!! 복붙해서. 만든두번째 while 문에서오류! 컴파일도잘되고실행시예외도던지지않기때문에발견어렵다. for 문을사용해야하는이유 a. b. 사용한원소와반복자변수의유효범위가반복문과함께끝나기때문에이러한버그예방할수있다. 가독성이좋다. 4. 메서드를작게유지하고한가지기능에집중하라. 한메서드에서여러기능을처리한다면그중한기능과만관련된지역변수라도다른기능을수행하는코드에서접근할수있다. 메서드를기능별로쪼개자. 아이템 58. 전통적인 for 문보다는 for-each 문을사용하라 코드 58-1 컬렉션순회하기 - 더나은방법이있다. for(iterator<element> i = c.iterator(); i.hasnext(); ){ Element e = i.next();... //e. 코드 58-2 배열순회하기 - 더나은방법이있다. for(int i = 0 ; i < a.length ; i ++){... // a[i]. 반복자와인덱스변수는코드를지저분하게하고, 변수를잘못사용할여지를준다. 해결방법 : for-each문사용 for-each문 = 향상된 for 문 (enchanced for statement) 반복자와인덱스를사용하지않아코드가깔끔하고, 오류날일도없다.

코드 58-3 elements 안의각원소 e 에대해 순회하는반복문. for(element e : elements){... // e. 코드 58-4 for-each 를쓰면좋은이유. 버그를찾아보자 enum Suit {CLUB, DIAMOND, HEART, SPADE enum RANK { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING... static Collection<Suit> suits = Arrays.asList(Suit.values()); static Collection<Rank> ranks = Arrays.asList(Rank.values()); List<Card> dec = new ArrayList<>(); for(iterator<suit> i = suits.iterator() ; i.hasnext(); ) for(iterator<rank> j = ranks.iterator(); j.hasnext();) dec.add(new Card(i.next(), j.next())); 문제점 : i.next next() 는 Suit 하나당한번씩만불려야하는데, 안쪽반복문에서호출되어 Rank 하나당한번씩불리고있음. > 숫자가바닥나면반복문에서 NoSuchElementException 발생. 코드 58-5 for-each 를쓰면좋은이유. 버그를찾아보자 2 enum face { ONE, TWO, THREE, FOUR, FIVE, SIX... Collection<Face> faces = EnumSet.allOf(Face.class); for(iterator<face> i = faces.iterator(); i.hasnext();) for(iterator<face> j = faces.iterator(); j.hasnext(); ) System.out.println(i.next() + " " + j.next()); // : 36 // : 6 // [ONE ONE] [TWO TWO] [THREE THREE] [FOUR FOUR] [FIVE FIVE] [SIX SIX] 예외를던지지는않지만, 실행시예상치못한결과를출력한다. 코드 58-7 for-each 문을중첩하여 58-5 버그해결 // for for(suit suit : suits) for (Rank rank : ranks) deck.add(new Card(suit, rank));

for-each 문을통해위의버그를해결할수있다. for each 사용할수없는경우세가지 a. b. c. 파괴적인필터링 (destructive filtering) 컬렉션을순회하면서선택된원소를제거해야한다면반복자의 remove 메소드를호출해야한다. 자바 8 부터는 Collection 의 removeif 메서드를사용해컬렉션을명시적으로순회하는일을피할수있다. 변형 (transforming) 리스트나배열을순회하면서그원소의값일부혹은전체를교체해야한다면리스트의반복자나배열의인덱스를사용해야한다. 병렬반복 (parallel iteration) 여러컬렉션을병렬로순회해야한다면각각의반복자와인덱스변수를사용해엄격하고명시적으로제어해야한다.( 코드 58-4) 위 a, b, c 의경우에는전통적 for 문사용. For-each 문은컬렉션과배열, Iterable 인터페이스를구현한객체라면무엇이든순회가능. 원소들의묶음을표현하는타입을작성해야한다면 Iterable 을구현하는쪽으로고민해보자! //for-each! Public interface Iterable<E>{ Iterator<E> iterator(); 전통적인 for 문과비교했을때 for-each 문은명료하고, 유연하고, 버그를예방해준다. 성능저하도없다. 가능한모든곳에서 for 문이아닌 for-each 문을사용하자. 아이템 59. 라이브러리를익히고사용하라 random 코드 59-1 흔하지만문제가심각한코드! static Random rnd = new Random(); static int random(int n){ return Math.abs(rnd.nextInt()) % n ; public static void main(string[] args){ int n = 2 * (Integer.MAX_VALUE / 3); int low = 0; for(int i = 0 ; i < 1000000; i ++) if(random(n) < n / 2) low ++; System.out.println(low); //random 50, 666,666. 1. 표준라이브러리를사용하면그코드를작성한전문가의지식과여러분보다앞서사용한다른프로그래머들의경험을활용할수있다.

자바 7 부터는 ThreadLocalRandom. 사용권장. Random 보다더고품질의무작위수생성, 더빠른속도. Thread Local Random 참고 2. 핵심적인일과관계없는문제를해결하느라시간을허비하지않아도된다. 애플리케이션기능개발에집중할수있다. 3. 따로노력하지않아도성능이지속해서개선됨 사용자가많고, 업체표준벤치마크를이용해성능을확인하기때문에표준라이브러리제작자들은더나은방법을꾸준히모색. 자바플랫폼라이브러리의많은부분이수년에걸쳐지속해서다시작성되며, 때론성능이극적으로개선되기도한다. 4. 기능이점점많아진다. 라이브러리에부족한부분이있다면개발자커뮤니티에서이야기가나오고논의된후다음릴리스에해당기능이추가됨. 5. 작성한코드가많은사람들에게낯익은코드가됨. 자연스럽게다른개발자들이더읽기좋고, 유지보수하기좋고, 재활용하기쉬운코드가됨. 이러한이점에도불구, 라이브러리의기능이있는지모르기때문에직접구현해서쓰는경우가많다. 메이저릴리스마다주목할만한수많은기능이라이브러리에추가된다. 코드 59-2 transferto 메서드를이용해 URL 의내용가져오기 - JAVA 9 부터가능 // 9 InputStream transferto. public static void main(string[] args) throws IOException{ try(inputstream in = new URL(args[0]).openStream()){ in.transferto(system.out); //?? java.lang, java.util., java.io 그하위패키지들에는익숙해져야한다. 언급된라이브러리들 1) java.util.concurrent : 동시성기능. 멀티스레드프로그래밍작업을단순화해주는고수준의편의기능, 능숙한개발자가자신만의고수준개념을직접구현할수있도록도와주는저수준의요소들제공. 2) 고품질의서드파티라이브러리 - 구글구아바 Guava 바퀴를다시발명하지말자. 아주특별한나만의기능이아니라면누군가이미라이브러리형태로구현해놓았을가능성이크다. 그런라이브러리가있다면, 쓰면된다. 있는지잘모르겠다면찾아보라. 일반적으로라이브러리의코드는여러분이직접작성한것보다품질이좋고, 점차개선될가능성이크다. 여러분의실력을폄하하는게아니다. 코드품질에도규모의경제가적용된다. 즉, 라이브러리코드는개발자각자가작성하는것보다주목을훨씬많이받으므로코드품질도그만큼높아진다. 아이템 60. 정확한답이필요하다면 float 와 double 은피하라

float 과 double 타입은과학과공학계산용으로설계됨. 이진부동소수점연산에쓰이며, 넓은범위의수를빠르게정밀한 근사치 로계산하도록세심하게설계. 정확한결과필요할때는사용하면안됨. 특히, 금융계산등.. 정확한값을요구하는계산에 double, float 사용하면안돼는예 // 0.1, 10. public static void main(string[] args) throws IOException{ System.out.println(1.03-0.42); // 0.610000000000000001 해결방법 : BigDecimal, int 혹은 long 사용. BigDecimal 사용시단점 : 기본타입보다쓰기힘들고, 느리다. 대안으로 int, long 사용가능. ( 단, 다룰수있는값의크기제한, 소수점직접관리해야함 ) 정확한답이필요한계산에는 float 이나 double 을피하라. 소수점추적은시스템에맡기고, 코딩시의불편함이나성능저하를신경쓰지않겠다면 BigDecimal 을사용하라. BingDecimal 이제공하는여덟가지반올림모드를이용하여반올림을완벽히제어할수있다. 법으로정해진반올림을수행해야하는비즈니스계산에서아주편리한기능이다. 반면, 성능이중요하고소수점을직접추적할수있고숫자가너무크지않다면 int 나 long 을사용하라. 숫자를아홉자리십진수로표현할수있다면 int 를사용하고, 열여덟자리십진수로표현할수있다면 long 을사용하라. 열여덟자리를넘어가면 BigDecimal 을사용해야한다. 아이템 61. 박싱된기본타입보다는기본타입을사용하라. Java 데이터타입 a. b. c. 기본타입 : int, double, boolean 참조타입 : String, List 각각의기본타입에는대응하는참조타입이하나씩있고, 이를박싱된기본타입이라고한다. ex. int-integer, double-double, boolean-boolean 기본타입과박싱된기본타입의차이세가지 기본타입은값만가지고있으나, 박싱된기본타입은값에더해식별성 (identity) 이란속성을갖는다. = 박싱된기본타입의두인스턴스는값이같아도서로다르다고식별될수있다. 기본타입의값은언제나유효하나, 박싱된기본타입은유효하지않은값 ( null ) 을가질수있다기본타입이박싱된기본타입보다시간과메모리사용면에서더효율적이다. 문제 ) 박싱된기본타입을잘못구현한예 이러한차이가있기때문에주의해서사용하자.

코드 61-1 잘못구현된비교자 //. // Integer i, j Comparator<Integer> naturalorder = ( i, j ) -> (i < j )? -1 : ( i == j? 0 : 1 ); naturalorder.compare(new Integer(42), new Integer(42)); // : Integer(42) == Integer(42) 0 // : 1 1. i < j : i 와 j 가참조하는오토언박싱된 Integer 인스턴스는기본타입값으로변환된다. i = 42, j =42 i 가 j 보다작지않기때문에, i == j 를수행, 2. i == j 에서두 객체참조 의식별성을검사하게됨. i 와 j 가서로다른 Integer 인스턴스라면비록값이같더라도비교결과가 false 가되고, 비교자는잘못된결과인 1 을반환하게됨. 즉, 첫번째 Integer 값이두번째보다크다는결과를반환하게된다. 이처럼박싱된기본타입에 == 연산자를사용하면오류가일어난다. 해결방안 ) 박싱된기본타입을잘못구현한예 코드 61-2 문제를수정한비교자 Comparator<Integer> naturalorder = (iboxed, jboxed) -> { int i = iboxed, j = j Boxed ; // return i < j? -1 : ( i == j? 0 : 1 ); ; // 2 Integer,. 실무에서이와같이기본타입을다루는비교자가필요하다면 Comparator.naturalOrder() 를사용하자. Comparator.naturalOrder() 사용예 public class ComparaTorNaturalOrder { public static void main(string[] args) { List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 6); numbers.sort(comparator.naturalorder()); System.out.println(numbers);

코드 61-3 이코드가돌아갈까요? public Class Unbelievable{ static Integer i; public static void main(string[] args){ if(i == 42) System.out.println("!"); // Null PointerException. i 의초기값이다른참조타입필드와동일하게 null 이기때문에, NullPointerException 발생 WHY? 기본타입과박싱된기본타입을혼용한연산에서는박싱된기본타입의박싱이자동으로풀린다. i 를 int 로선언해주자. 기본타입과박싱타입의차이를이해하고, 적절히사용하자 그렇다면박싱된타입은언제써야하는가? 컬렉션의원소, 키, 값으로사용. 컬렉션은기본타입을담을수없으므로박싱된기본타입을사용해야함 = 매개변수화타입이나매개변수화메서드 (5 장 ) 의타입매개변수로박싱된기본타입사용. 자바언어가타입매개변수로기본타입을지원하지않기때문 ex. ThreadLocal<int> (x), ThreadLocal<Integer> (o) 리플렉션을통해메서드를호출할때도박싱된기본타입을사용해야한다. 기본타입과박싱된기본타입중하나를선택해야한다면가능하면기본타입을사용하라. 기본타입은간단하고빠르다. 박싱된기본타입을써야한다면주의를기울이자. 오토박싱이박싱된기본타입을사용할때의번거로움을줄여주지만, 그위험까지없애주지는않는다. 두박싱된기본타입을 == 연산자로비교한다면식별성비교가이뤄지는데, 이는여러분이원한게아닐가능성이크다. 같은연산에서기본타입과박싱된기본타입을혼용하면언박싱이이뤄지며, 언박싱과정에서 NullPointerException 을던질수있다. 마지막으로, 기본타입을박싱하는작업은필요없는객체를생성하는부작용을낳을수있다. Item62. 다른타입이적절하다면문자열사용을피하라. String : 텍스트표현하도록설계됨. 그러나원래의도하지않은용도로쓰이는경향이있다. String 을쓰지않아야할사례 1. 문자열은다른값타입을대신하기에적절하지않다. 입력받을데이터가진짜문자열일때만사용하자. 받은데이터가수치형 : int, float, BigInteger 등적당한수치타입으로변환예 / 아니오등의답 : boolean 변환. 기본타입이든참조타입이든적절한값타입이있다면그것을사용하고, 없다면새로작성하자. 2. 문자열은열거타입을대신하기에적합하지않다. 아이템 34 에서이야기했듯, 상수를열거할때는문자열보다는열거타입이월등히낫다. - public static final String a = A ; 보다는 enum { A ; 3. 문자열은혼합타입을대신하기에적합하지않다. ex. String compoundkey = classname + # + i.next(); # 이두요소중하나에서쓰였다면혼란스러운결과를초래한다. 각요소를개별로접근하려면문자열을파싱해야해서느리고, 오류가능성도커짐. String 이제공하는기능에만의존해야한다. Private 정적멤버클래스로선언하자. ( 아이템 24 )

4. 문자열은권한을표현하기에적합하지않다. 코드 62-2 잘못된예 - 문자열을사용해권한을구분하였다. //. public Class ThreadLocal(){ private ThreadLocal(); //. public static void set(string key, Object value); //( ). public static Object get(string key); 문제점 : 스레드구분용문자열키가전역이름공간에서공유된다. 만약두클라이언트가같은키를사용하게된다면?? 의도치않게같은변수를공유하게됨.! 보안상으로도, 다른클라이언트값을가져올수도있기때문에취약하다. 문자열대신위조할수없는키를사용하자 더적합한데이터타입이있거나새로작성할수있다면, 문자열을쓰고싶은유혹을뿌리쳐라. 문자열은잘못사용하면번거롭고, 덜유연하고, 느리고, 오류가능성도크다. 문자열을잘못사용하는흔한예로는기본타입, 열거타입, 혼합타입이있다. 아이템 63. 문자열연결은느리니주의하라. 문자열연결연산자 + 여러문자열을하나로합쳐주는편리한수단. but, 문자열연결연산자로문자열 n 개를잇는시간은 n² 에비례. 문자열은불변 (item17) 이라서두문자열을연결할경우양쪽의내용을모두복사해야하므로성능저하초래. String 대신 StringBuilder 를사용하자. 아이템 64. 객체는인터페이스를사용해참조하라. 적합한인터페이스만있다면매개변수뿐아니라반환값, 변수, 필드를전부인터페이스타입으로선언하라. 객체의실제클래스를사용해야할상황은 오직 생성자로생성할때만. 좋은예 : 인터페이스를타입으로사용. Set<Son> sonset = new LinkedHashSet<>(); 나쁜예 : 클래스를타입으로사용. LinkedHashSet<Son> sonset = new LinkedHashSet<>(); 인터페이스를타입으로사용하는습관을길러두면프로그램이훨씬유연해짐. Set<Son> sonset = new HashSet<>(); 주의할점 : 나중에구현클래스교체하더라도새클래스의생성자를호출해주면됨. 원래클래스가인터페이스의일반규약이외의특별한기능을제공하며, 주변코드가이기능에기대어동작한다면새로운클래스도반드시같은기능제공해야함. LinkedHashSet HashSet 으로바꿀경우, 전자의순서정책에따라동작하는코드의경우문제가될수있다.

a. b. c. HashSet 은순서보장을하지않기때문. 그렇지만, 적합한인터페이스가없다면당연히클래스로참조해야한다. String 과 BigInteger 값클래스. 클래스기반으로작성된프레임워크가제공하는객체들. OutputStram 등 java.io 패키지의여러클래스. 인터페이스에는없는특별한메서드를제공하는클래스들. PriorityQueue 클래스는 Queue 인터페이스에는없는 comparator 메서드를제공. 실전에서는주어진객체를표현할적절한인터페이스가있는지찾아서그인터페이스를참조하면더유연하고세련된프로그램을만들수있다. 적합한인터페이스가없다면클래스의계층구조중필요한기능을만족하는가장덜구체적인 ( 상위의 ) 클래스를타입으로사용하자. 아이템 65. 리플렉션보다는인터페이스를사용하라. 리플렉션기능 (java.lang.reflect) 을이용하면프로그램에서임의의클래스에접근할수있다. Class 객체가주어지면그클래스의생성자, 메서드, 필드에해당하는 Constructor, Method, Field 인스턴스가져올수있고, 인스턴스들로는클래스멤버이름, 필드타입, 메서드시그니처등을가져올수있다. Method.invoke 사용해메서드호출도가능리플렉션을이용하면컴파일당시에존재하지않던클래스도이용할수있는데, 단점도있다. 리플렉션기능의단점 1. 컴파일타임타입검사가주는이점을하나도누릴수없다. 프로그램이리플렉션기능을써서존재하지않는혹은접근할수없는메서드를호출하려시도하면런타임오류가발생. 2. 리플렉션을이용하면코드가지저분하고장황해진다. 지루하고, 읽기어렵다. 3. 성능이떨어진다. 리플렉션을통한메서드호출은일반메서드호출보다훨씬느리다. 입력매개변수없고 int만반환하는메소드호출시 11배나느린실행결과. 리플렉션필요성에대한확신이없다면아마도필요없을가능성이크다. 리플렉션은아주제한도니형태로만사용해야그단점을피하고이점만취할수있다. 리플렉션은복잡한특수시스템을개발할때필요한강력한기능이지만, 단점도많다. 컴파일타임에는알수없는클래스를사용하는프로그램을작성한다면리플렉션을사용해야할것이다. 단, 되도록객체생성에만사용하고, 생성한객체를이용할때는적절한인터페이스나컴파일타임에알수있는상위클래스로형변환해사용해야한다. 아이템 66. 네이티브메서드는신중히사용하라. 자바네이티브인터페이스 (Java Native Interface, JNI) 는자바프로그램이네이티브메서드 (C, C++ 같은네이티브프로그래밍언어로작성한메서드 ) 를호출하는기술이다. 전통적네이티브메서드의주요쓰임 a. b. c. 레지스트리같은플랫폼특화기능사용네이티브코드로작성된기존라이브러리를사용성능개선을목적으로성능에결정적인영향을주는영역만따로네이티브언어로작성한경우. 플랫폼특화기능을활용하려면네이티브메서드를사용해야하지만, 자바가성숙해가면서하부플랫폼들의기능들을점차흡수하고있다.

성능개선목적등으로네이티브메서드사용은권장하지않는다. 네이티브언어는자바보다플랫폼을많이타서이식성도낮고, 디버깅도어렵다. 네이티브메서드를사용하려거든한번더생각하라. 네이티브메서드가성능을개선해주는일은많지않다. 저수준자원이나네이티브라이브러리를사용해야만해서어쩔수없더라도네이티브코드는최소한만사용하고철저히테스트하라. 네이티브코드안에숨은단하나의버그가여러분의어플리케이션전체를훼손할수도있다. 아이템 67. 최적화는신중히하라. 최적화의어두운진실. ( 맹목적인어리석음을포함해 ) 그어떤핑계보다효율성이라는이름아래행해진컴퓨팅죄악이더많다 ( 심지어효율을높이지도못하면서 )" - 윌리엄울프 [Wulf72] "( 전체의 97% 정도인 ) 자그마한효율성은모두잊자. 섣부른최적화가만악의근원이다." - 도널드크누스 [Knuth74] " 최적화를할때는다음두규칙을따르라. 첫번째, 하지마라. 두번째, ( 전문가한정 ) 아직하지마라. 다시말해, 완전히명백하고최적화되지않은해법을찾을때까지는하지마라." - M.A 잭슨 [Jackson75] 성능때문에견고한구조를희생하지말자. 1) 빠른프로그램보다는좋은프로그램을작성하라. 아키텍처자체가최적화할수있는길을안내해줄것이다. 시스템나머지에영향을주지않고도각요소를다시설계할수있다. 구현상의문제는나중에최적화해해결할수있지만, 아키텍처의결함이성능을제한하는상황이라면시스템전체를다시작성하지않고는해결하기불가능할수있다. 설계단계에서성능을염두해야한다. 2) 성능을제한하는설계를피하라. APi, 네트워크프로토콜, 영구저장용데이터포맷등설계요소등은완성후변경이어렵거나불가능하며, 시스템성능에심각한영향을끼칠수있으므로초기에적절히.. 3) API 설계할때성능에주는영향을고려하라. 빠른프로그램을작성하려안달하지말자. 좋은프로그램을작성하다보면성능은따라오게마련이다. 하지만시스템을설계할때, 특히 API, 네트워크프로토콜, 영구저장용데이터포맷을설계할때는성능을염두해두어야한다. 시스템구현을완료했다면이제성능을측정해보라. 충분히빠르면그것으로끝이다. 그렇지않다면프로파일러를사용해문제의원인이되는지점을찾아최적화를수행하라. 가장먼저어떤알고리즘을사용했는지살펴보라. 알고리즘을잘못골랐다면다른저수준최적화는아무리해봐야소용이없다. 만족할때까지이과정을반복하고, 모든변경후에는성능을측정하라. 아이템 68. 일반적으로통용되는명명규칙을따르라.

자바플랫폼은명명규칙이잘정립되어있으며, 크게철자와문법두범주로나뉜다. 참조 : 자바언어명세 [JLS, 6.1] 철자규칙 : 패키지, 클래스, 인터페이스, 메서드, 필드, 타입의변수의이름명명규칙. 이규칙들은특별한이유가없는한반드시따라야한다. 이규칙을어긴 API 는사용하기어렵고, 유지보수하기어렵다. 읽기번거로운코드, 다른뜻으로오해하고그로인한오류야기. 패키지와모듈이름은각요소를. 으로구분하여계층짓는다. 조직밖에서도사용될패키지라면조직의인터넷도메인역순으로사용. ex. com.google. 예외 : 표준라이브러리, 선택적패키지들 java, javax 로시작. 패키지이름각요소는 8 자이하짧은단어 (utilities 보단 util, awt 처럼약어사용 ) 클래스와인터페이스의이름은하나이상의단어로이루어지며, 각단어는대문자로시작. 여러단어는첫글자만대문자. 널리통용되는줄임말외에는줄여쓰지말자. 메서드와필드이름은첫글자를소문자로쓴다는점외에는클래스명명규칙과같다. 단, 상수필드 는제외. 상수필드는모두대문자로사용. 지역변수다른멤버변수와비슷한명명규칙적용. 약어사용해도그변수가사용되는문맥에서의미쉽게유추되기때문에사용해야된다. 입력매개변수의경우메서드설명문서에까지등장하는만큼지역변수보다는신경을써야한다. 타입매개변수 : 이름을보통한문자로표현. T : 임의의타입 type E : 컬렉션원소의타입 Element K : 맵의키 Key V : 맵의값 Value X : 예외 exception R : 메서드의반환타입 Return T, U, V / T1, T2, /T3 : 임의타입의시퀀스 문법규칙 : 더유연하고논란도많다. 객체의타입을바꿔서다른타입의또다른객체를반환하는인스턴스메서드 totype 으로명명 > tostring, toarray. 객체의내용을다른뷰로보여주는메서드 astype --> aslist 객체의값을기본타입으로반환하는메서드이름 typevalue --> intvalue 정적팩터리의이름은다양하지만 from, of, valueof, instance, getinstance, newinstance, gettype, newtyep 흔히사용. 표준명명규칙을체화하여자연스럽게베어나오도록하자. 철자규칙은직관적이라모호한부분이적은데반해, 문법규칙은더복잡하고느슨하다. 자바언어명세 [JLS, 6.1] 의말을인용하자면 오랫동안따라온규칙과충돌한다면그규칙을맹종해서는안된다. 상식이이끄는대로따르자.