반응형

출처 : 이것이 자바다

17.1 JavaFX 개요

JavaFX는 크로스 플랫폼에서 실행하는 리치 클라이언트 애플리케이션을 개발하기 위한 그래픽과 미디어 패키지를 말한다.

JAVA 7부터 JDK에 포함되어 있기때문에 별도의 SDK 설치 없이도 바로 사용할 수 있다.

AWT  네이티브 UI컴포넌트를 이용해서 개발하였다.  

Swing 운영체제가 제공하는 네이티브 UI컴포넌트를 사용하지 말자는 것이다.

JavaFX 는 어도비의 플래쉬 와 마이크로소프트의 실버라이트의 대항마로 만들어졌다.

 

17.2 JavaFX 애플리케이션 개발 시작

17.2.1 메인 클래스

javafx.application.Application 을 상속받고 , start() 메소드 재정의

17.2.2 JavaFX라이프사이클

Application.launch()메소드부터 시작해서 

17.2.3 메인 클래스 실행 매개값 얻기

init() 메소드의 역할은 메인 클래스의 실행 매개값을 얻어 애플리케이션의 초기값으로 이용할 수 있도록 하는 것이다.

17.2.4 무대(Stage)와 장면(Scene)

 

17.3 JavaFX 레이아웃

17.3.1 프로그램적 레이아웃

자바 코드로 ui컨트롤을 배치하는 것을 말한다.

 

17.3.2 FXML레이아웃

XML기반의 마크업 언어로 , JavaFX 어플리케이션의 UI레이아웃 을 자바 코드에서 분리해서 태그로 선언하는 방법을 제공한다.

 

17.3.3 레이아웃 여백: 피딩과 마진

패딩은 안쪽 여백을 말하고 마진은 바깥 여백을 말한다.

17.3.4 FXML 작성 규칙

자바 코드로 변환되어 실행되기 때문에 자바 코드와 매핑 관계가 존재한다.

17.3.5 FXML 로딩과 Scene생성

 

17.3.6 JavaFX Scene Builder

 

17.4 JavaFX 컨테이너 

17.4.1 AnchorPane 컨테이너 

좌표를 이용하여 AnchorPane의 좌상단(0,0)을 기준으로 컨트롤을 배치한다.

17.4.2 HBox와 VBox 컨테이너 

수평과 수직으로 컨트롤을 배치하는 컨테이너이다.

17.4.3 BorderPane 컨테이너

top, bottom, left, right, center 셀에 컨트롤을 배치하는 컨테이너이다.

17.4.4 FlowPane 컨테이너

행으로 컨트롤을 배치하되 공간이 부족하면 새로운 행에 배치하는 컨테이너이다.

17.4.5 TilePane 컨테이너

그리드로 컨트롤을 배치하되 고정된 셀 (타일)크기를 갖는 컨테이너이다.

17.4.6 GridPane 컨테이너 

그리드로 컨트롤을 배치하되 셀의 크기가 고정적이지 않고 유동적인 컨테이너이다.

17.4.7 StackPane켄테이너 

StackPane은 컨트롤을 겹쳐 배치하는 컨테이너이다. 

 

17.5 JavaFX 이벤트 처리

17.5.1 이벤트 핸들러 

JavaFX 는 이벤트 발생 컨트롤과 이벤트 핸들러를 분리하는 위임형방식을 사용한다.

 

17.6 JavaFX 속성 감시와 바인딩

17.6.1 속성 감시

세가지 메소드

Getter

Setter

Property

17.6.2 속성 바인딩

17.6.3 Bindings클래스

두 속성이 항상 동일한 값과 타입을 가질 수 는 없다.

 

17.7 JavaFX 컨트롤

17.7.1 버튼 컨트롤

Button()

 

17.7.2 입력 컨트롤

TextField

 

17.7.3 뷰 컨트롤

ImageView컨트롤

ListView 컨트롤

TableView 컨트롤

17.7.4 미디어 컨트롤

17.7.5 차트 컨트롤

 

17.8 JavaFX메뉴바와 툴바

17.8.1 MenuBar 컨트롤

17.8.2 Toolbar 컨트롤

 

17.9 JavaFX 다이얼로그

17.9.1 FileChooser, DirectoryChooser

17.9.2 Popup

17.9.3 커스팀 다이얼로그

17.9.4 컨트롤러에서 primaryStage상요

메인 클레스에서 전달하는 방법

컨테이너 또는 컨트롤러부터 얻는 방법

 

17.10 JavaFX CSS스타일

모양 및 색상 등을 변경할 수 있다.

 

17.10.1 인라인 스타일

17.10.2 외부 CSS파일

선택자

CSS파일 적용

17.10.3 border 속성

17.10.4 background속성

배경 스타일 설정

17.10.5 font속성

17.10.6 shadow 효과

17.10.7 화면 스킨 입히기

 

17.11 JavaFX 스레드 동시성

17.11.1 Platform, runLater() 메소드

17.11.2 Task클래스

Task 생성

Task는 작업 스레드에서 실행되는 하나의 작업을 표현한 추상 클래스이다.

17.11.3 Service 클래스

작업 스레드상에서 tASK를 간편하게 시작 , 취소 , 재시작할 수 있는 기능을 제공한다.

 

17.12 화면 이동과 애니메이션

17.12.1 화면 이동

17.12.2 애니메이션

 

 

18. IO 기반 입출력 및 네트워킹

18.1 IO패키지 소개

프로그램에서는 데이터를 외부에서 읽고 다시 외부로 출력하는 작업이 빈번히 일어난다.

 

18.2 입력 스트림과 출력 스트림

InputStream, OutputStream()

 

18.2.1 InputStream

read()메소드

read(byte[] b)메소드

18.2.2 OutputStream

write(int b)

write(byte[] b)메소드

write(byte[] b, int off, int len)메소드

flush와 close()메소드

18.2.3 Reader 

read()메소드

read(char[] cbuf)메소드

read(char[] cbuf, int off, int len)메소드

close()메소드

18.2.4 Writer

 

18.3 콘솔 입출력

18.3.1 System.in필드

18.3.2 System.out필드

18.3.3 Console 클래스

18.3.4 Scanner 클래스

 

18.4 파일 입출력

18.4.1 File 클래스

18.4.2 FileInputStream

18.4.3 FileOutputStream

18.4.4 FileReader

18.4.5 FileWriter

 

18.5 보조 스트림

18.5.1 문자 변환 보조 스트림

18.5.2 성능 향상 보조 스트림

Buffer....

18.5.3 기본 타입 입출력 보조 스트림

18.5.4 프린터 보조 스트림

18.5.5 객체 입출력 보조 스트림

 

18.6 네트워크 기초

18.6.1 서버와 클라이언트

18.6.2 ip주소와 포트

ip주소는 네트워크 어댑터마다 할당되는데, 한 개의 컴퓨터에 두 개의 네트워크 어댑터가 장착되어 있다면, 두개의 ip주로슬 할당 할 수 있다.

18.6.3 InetAddress로 IP주소 얻기

InetAddress.getLocalHost();

 

18.7 TCP 네트워킹

tcp transmission control protocol는 연결 지향적 프로토콜이다.

단점 " 데이터를 보내기 전에 반드시 연결이 형성되어야 하고 (가장 시간이 많이 걸리는 작업), 고정된 통신 선로가 최단선(네트워크 길이 측면) 이 아닐 경우 상대적으로 udp(user datagram protocol)보다 데이터 전송 속도가 느릴 수 있다. 

 

18.7.1 ServerSocket과 Socket의 용도

서버가 실행되면 클라이언트는 서버가 ip주소와 바인딩 포트 번호로 Socket을 생성해서 연결 요청을 할 수있다.

18.7.2 ServerSocket 생성과 연결 수락

18.7.3 Socket 생성과 연결 요청

18.7.4 Socket데이터 통신

18.7.5 스레드 병렬 처리

18.7.6 채팅 서버 구현

18.7.7 채팅 클라이언트 구현

 

18.8 udp네트워킹

udp는 비연결 지향적 프로토콜이다.

비연결 지향적이란 데이터를 주고받을 때 연결 절차를 거치지 않고, 발신자가 일방적ㅇ로 데이터를 발신하는 방식이다.

18.8.1 발신자 구현

18.8.2 수신자 구현

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

16. 스프림과 병렬 처리  (0) 2020.10.17
15. 컬렉션 프레임워크  (0) 2020.10.13
13. 제네릭 14. 람다식  (0) 2020.10.10
12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
반응형

출처 : 이것이 자바다

 

16.1 스트림 소개

스트림은 자바8부터 추가된 컬렉션 (배열 포함) 의 저장 요소를 하나씩 참조해서 람다식 (함수적 - 스타일(functional-style))으로 처리 할 수 있도록 해주는 반복자이다.

 

16.1.1 반복자 스트림

자바 7 이전 까지는 List<String> 컬렉션에서 요소를 순차적으로 처리하기 위해 Iterator 반복자 사용

 

Stream으로 변경 한다.

 

16.1.2 스트림의 특징

Stream은 Iterator와 비슷한 역할을 하는 반복자이지만, 람다식으로 요소 처리 코드를 제공하는 점과 내부 반복자를 사용하므로 병렬 처리가 쉽다는 점 그리고 중간 처리와 최종 처리 작업을 수행하는 점에서 많은 차이를 가지고 있다. 

 

람다식으로 요소 처리 코드를 제공한다.

내부 반복자를 사용하므로 병렬처리가 쉽다.

스트림은 중간 처리와 최종 처리를 할 수 있다.

 

16.2 스트림의 종류

Stream 

IntStream, LongStream, DoubleStream

 

16.2.1 컬렉션으로부터 스트림 얻기

 

16.2.2 배열로 부터 스트림 얻기

 

16.2.3 숫자 범위로 부터 스트림 얻기

 

16.2.4 파일로부터 스트림 얻기

 

16.2.5 디렉토리로부터 스트림 얻기

 

16.3  스트림 파이프라인

대량의 데이터를 가공해서 축소하는 것을 일반적으로 리덕션이라고 한다.

 

16.3.1 중간 처리와 쵲ㅇ 처리

푀종처리를 파이프라인으로 해결한다.

 

지연 (lazy)

 

16.3.2 중간 처리 메소드와 최종 처리 메소드

리턴 타입으로 구분한다.

 

16.4 필터링(distinct(), filter())

필터링은 중간 처리 기능으로 요소를 걸러내는 역할을 한다.

distinct() 중복을 제거

 

16.5 매핑(flatMapXXX(), mapXXX(), asXXXStream(), boxed())

16.5.1 flatMapXXX()메소드 

요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림을 리턴한다.

16.5.2 mapXXX()메소드

요소를 대체하는 요소로 구성된 새로운 스트림을 리턴한다.

16.5.3 asDoubleStream(),asLongStream(), boxed()메소드

asDoubleStream() IntStream의 int 요소 또는 LongStream의 long요소를 double요소로 타입 변환해서 DoubleStream을 생성

asLongStream() IntStream의 int 요소를 long 요소로 타입 변환해서 LongStream을 생성

boxed() int ,long, double요소를 Integer, Long, Double요소로 박싱해서 Stream을 생성한다.

 

16.6 정렬(sorted())

스트림은 요소가 최종 처리되기 전에 중단 단계에서 요소를 정렬해서 최종 처리 순서를 변경할 수 있다.

sorted()

Comparable 

 

16.7 루핑(peek(), forEach())

루핑은 요소 전체를 반복하는 것을 말한다. 

루핑하는 메소드에는 peek(), forEach()

peek 중간 처리 메소드이고 

forEach() 최종 처리 메소드이다.

 

16.8 매칭(allMatch(), anyMach(),nonMatch())

allMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 조사하고 

anyMach() : 최소한 한 개의 요소가 매개값으로 주어진 Predicate의 조건을 만족하는지 조사한다.

nonMatch() : 모든 요소들이 매개값으로 주어진 Predicate 의 조건을 만족하지 않는지 조사한다.

 

16.9 기본 집계(sum(), count(), average(), max(), min())

집계는 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계 , 평균값, 최대값, 최소값 등과 같이 하나의 값으로 산출하는 것을 말한다.

 

16.9.1 스트림이 제공하는 기본 집계

OptionalXXX는 자바 8에서 추가한 java.util패키지

 

16.9.2 Optional 클래스

저장하는 값의 타입만 다를 뿐 제공하는 기능은 거의 동일하다.

 

16.10 커스텀 집계(reduce())

sum(), average(), count(), max(), min()을 제공

프로그램화해서 다양한 집계 결과물을 만들 수 있도록 reduce()메소드에 제공한다.

 

16.11 수집(collect())

스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메소드인 collect()를 제공하고 있다.

 

16.11.1 필터링한 요소 수집

Stream의 collect(Collector<T, A,R> collector)메소드는 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고 , 이 컬렉션을 리턴한다.

 

16.11.2 사용자 정의 컨테이너에 수집하기

collect()

 

16.11.3 요소를 그루핑해서 수집

collect()메소드는 단순히 요소를 수집하는 기능 이외에 컬렉션의 요소들을 그룹핑해서 Map객체를 생성하는 기능도 제공한다.

groupingBy() 또는 groupingByConcurrent()가 리턴하는 Collector를 매개값으로 대입하면 된다.

 

16.11.4 그룹핑 후 매핑 및 집계

Collectors.groupingBy()메소드는 그룹핑 후 , 매핑이나 집계( 평균, 카운팅, 연결, 최대 , 최소, 합계)를 할 수 있도록 두 번째 매개값으로 Collector를 가질 수 있다.

 

 

16.12 병렬처리

멀티 코어 cpu환경에서 하나의 작업을 분할해서 각각의 코어가 병렬적으로 처리하는 것을 말하는데, 병렬처리의 목적은 작업 처리 시간을 줄이기 위한 것이다.

 

16.12.1 동시성 과 병렬성

16.12.2 포크조인(ForkJoin)프레임워크

병렬 스트림은 요소들을 병렬 처리하기 위해 포크조인 프레임워크를 사용한다.

 

16.12.3 병렬 스트림 생성

 

16.12.4 병렬 처리 성능

요소의 수와 요소당 처리 시간

스트림 소스의 종류

코어(Core)의 수

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

17. JavaFX 18. IO 기반 입출력 및 네트워킹  (0) 2020.10.23
15. 컬렉션 프레임워크  (0) 2020.10.13
13. 제네릭 14. 람다식  (0) 2020.10.10
12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
반응형

출처 : 이것이 자바다

15.1 컬렉션 프레임워크 소개

필요할 떄마다 꺼내서 사용하는 경우가 많다. 

배열은 쉽게 생성하고 사용할 수 있지만 ,저장할 수 있는 객체 수가 배열을 생성할 때 결정되기 때문에 불특정 다수의 개게를 저장하기에는 문제가 있다. 

배열의 또 다른 문제점은 객체를 삭제했을 떄 해당 인덱스가 비게 되어 낱일이 듬성듬성 빠진 옥수수가 될 수 있다.

 

컬렉션이란 사전적 의미로 요소를 수집해서 저장하는 것 을 말하는데, 자바 컬렉션은 객체를 수집해서 저장하는 역할을 한다.

프레임워크란 사용 방법을 미리 정해 놓은 라이브러리를 말한다.

List, Set, Map =>인터페이스 

ArrayList, Vecotr, LinkedList =>List 인터페이스

HashSet, TreeSet =>set인터페이스

HashMap, Hashtable, TreeMap, Properties =>Map 인터페이스

List와 Set은 객체를 추가, 삭제 , 검색하는 방법에 많은 공통점이 있기 때문에 이 인터페이스들의 공통된 메소드들만 모아 Collection 인터페이스로 정의해 두고 있다.

Map은 키와 값을 하나의 쌍으로 묶어서 관리하는 구조로 되어 있어 , List 및 Set과는 사용방법이 완전히 다르다.

 

15.2 List 컬렉션

객체를 일렬로 늘어놓은 구조를 가지고 있다.

인덱스가 부여되고 인덱스로 객체를 검색, 삭제 할 수 있는 기능을 제공

 

15.2.1 ArrayList

List 인터페이스의 구현 클래스로 , 객체를 추가하면 객체가 인덱스로 관리된다.

일반 배열과 인덱스로 객체를 관리한다는 점에서는 유사하지만, 큰 차이점을 가지고 있다.

배열은 생성할 때 크기가 고정되고 사용 중에 크기를 변경할 수 없지만, ArrayList는 저장 용량을 초과한 객체들이 들어오면 자동적으로 저장용량이 늘어난다는 것이다.

 

15.2.2 Vector

ArrayList와 동일한 내부 구조를 가지고 있다.

List<E> list = new Vector<E>();

 

ArrayList와 다른 점은 Vector는 동기화된 메소드로 구성되어 있기 때문에 

멀티스레드가 동시에 이 메소드들을 실행할 수 없고, 하나의 스레드가 실행을 완료해야만

다른 스레드를 실행할 수 있다.

thread safe : 그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제 가능

 

15.2.3 LinkedList

LinkedList는 List 구현 클래스이므로 ArrayList와 사용방법은 똑같지만 내부 구조는 완전 다르다.

ArrayList 는 내부 배열에 객체를 저장해서 인덱스로 관리

LinkedList 인접 참조를 링크해서 체인처럼 관리한다.

LinkedList에서 특정 인덱스의 객체를 제거하면 앞뒤 링크만 변경되고 나머지 링크는 변경되지 않는다.

 

15.3 Set 컬렉션

객체를 중복해서 저장할 수 없고  , 하나의 null만 저장할 수 있습니다.

HashSet, LinkedHashSet, TreeSet

객체 추가 add()

객체 삭제 remove()

Iterator에서 하나의 객체를 가져올 때 next()메소드

hasNext()메소드는 가져올 객체가 있으면 true를 리턴하고 더 이상 객체가 없으면

false를 리턴한다.

 

15.3.1 HashSet

Set<E> SET = new HashSet<E>();

순서 없이 저장하고 동일한 객체는 중복 저장하지 않는다.

 

HashSet은 객체를 저장하기 전에 먼저 객체의 hashCode() 메소드 호출

equals() 두 객체 비교 

 

15.4 Map 컬렉션

키와 값으로 구성된 Entry 객체를 저장하는 구조를 가지고 있다.

객체 추가 put()

객체 삭제 remove()

키를 알고 있다면 get()

keySet() 

entrySet()

 

15.4.1 HashMap => Map 대표 컬렉션

HashMap 의 키로 사용할 객체는 hashCode()와 equals()메소드를 재정의해서 동등 객체가 될 조건을 

정해야 한다. 

 

15.4.2 

Hashtable 은 HashMap과 동일한 내부 구조를 가지고 있다. 

Hashtable 도 키로 사용할 객체는 hashCode()와 equals()메소드를 재정의 해서 

동등 객체가 될 조건을 정해야 한다.

차이점은 HashTable은 동기화된 메소드로 구성되어 있기 떄문에 멀티 스레드가 동시에 이 

메소드들을 실행할 수 는 없고 , 하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 

수 있다.

스레드가 안전

 

15.4.3 Properties

Properties는 Hashtable 의 하위 클래스이기 때문에 Hashtabl의 모든 특징을 그대로 가지고 있다.

차이점은 Hashtable 은 키와 값을 다양한 타입으로 지정이 가능한데 비해 

Properties는 키와 값을 String타입으로 제한한 컬렉션이다.

 

15.5 검색 기능을 강화시킨 컬렉션

15.5.1 이진 트리 구조

이진 트리는 여러 개의 노드 가 트리 형태로 연결된 구조로 , 루트 노드 라고 불리는 하나의 노드에서 부터 시작해서 각 노드에 최대 2개의 노드를 연결할 수 있는 구조를 가지고 있다.

 

15.5.2 TreeSet

이진 트리를 기반으로 Set 컬렉션이다. 

하나의 노드는 노드 값인 value와 왼쪽과 오른쪽 자식 노드를 참조가히 위한 두 개의 변수로 구성한다.

 

15.5.3 TreeMap

이진 트리를 기반으로 한 Map 컬렉션이다.

TreeSet,과 차이점은 키와 값이 저장된 Map.Entry를 저장한다는 점이다. 

 

15.5.4 Comparable과 Comparator

Comparable에는 compareTo()메소드가 정의되어 있기 때문에 사용자 정의 클래스에서는 이 메소드를 오버라이딩하여 사용

 

15.6 LIFO와 FIFO컬렉션

후입선출(LIFO) : 은 나중에 넣은 객체가 먼저 빠져나가는 자료구조를 말한다.

선입선출(FIFO) : 은 먼저 넣은 객체가 먼저 빠져나가는 구조를 말한다.

 

15.6.1 Stack

LIFO자료구조를 구현한 클래스이다. 

 

15.6.2 Queue

FIFO자료 구조에서 사용되는 메소드를 정의하고 있다.

 

15.7 동기화된 컬렉션

sysnchronized

Collections.synchronizedList()

 

15.8 병렬 처리르 위한 컬렉션

동기환된 컬렉션은 멀티 스레드 환경에서 하나의 스레드가 요소를 안전하게 처리하도록 도와주지만, 전체 요소를 빠르게 처리하지는 못한다.

 

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

17. JavaFX 18. IO 기반 입출력 및 네트워킹  (0) 2020.10.23
16. 스프림과 병렬 처리  (0) 2020.10.17
13. 제네릭 14. 람다식  (0) 2020.10.10
12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
반응형

출처 : 이것이 자바다

13.1 왜 제너릭을 사용해야 하는가 ?

java 5부터 제네릭(generic)타입이 새로 추가되었는데 , 제네릭 타입을 이용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있게 되었다. 

제네릭은 클래스와 인터페이스, 그리고 메소드를 정의할 때 타입 을 파라미터로 사용할 수있도록 한다.

 

컴파일 시 강한 타입 체크를 할 수 있다.

 

타입 변환(casting)을 제거한다.

비제네릭 코드는 불필요한 타입 변환을 하기 때문에 프로그램 성능에 악영향을 미친다.

 

13.2 제네릭 타입(class<T>, interface<T>)

제네릭 타입은 타입을 파라미터로 가지는 클래스의 인터페이스를 말한다.

<> 부호가 붙고  사이에 타입 파라미터가 위치한다.

Object 클래스는 모든 자바 클래스의 최상위 조상(부모)클래스이다.

 

13.3 멀티 타입 파라미터(class<K,V...>, interface<K,V,...>)

제네릭 타이은 두개 이상의 멀티 타입 파라미터를 사용할 수 있는데 , 이 경우 각 타입 파라미터를 콤마로 구분한다.

 

자바 7부터 제공

 

13.4 제네릭 메소드(<T,R> R mehod<T t>)

제네릭 메소드는 매개 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 말한다.

compare()

 

13.5 제한된 타입 파라미터(<T extends 최상위 타입>)

Number

 

13.6 와일드 타입(<?>, <? extends ...>, <? super ...>)

제네릭타입<?> : Unbounded Wildcards(제한 없음)

타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스, 인터페이스 타입이 올 수 있음.

제네릭타입<? extends 상위타입> : Upper Bounded Wildcards(상위 클래스 제한)

타입 파라미터를 대치하는 구체적  타입으로 상위타입이나 하위 타입만 올 수 있음.

제네릭타입<? super 하위 타입> : Lower Bounded Wildcards(하위 클래스 제한)

타입 파라미터를 대치하는 구체적 타입으로 하위 타입이나, 상위 타입만 올 수 있음.

 

 

 

14.1 람다식이란?

자바8부터 람다식 lambda expressions을 지원하면서 기존의 코드 패턴이 많이 달라졌다.

익명함수 anonymous function

람다식 -> 매개 변수를 가진 코드 블록 -> 익명 구현 객체 

익명 구현 

Runnable runnable = new Runnable() {
    public void run() { ... }
} ;

람다식 

Runnable runnable = () -> { ... };

(매개변수) -> {실행코드}

 

14.2 람다식 기본 문법

(타입 매개변수, ...) -> {실행문; ... }

() -> {실행문 ; .... }

 

14.3 타겟 타입과 함수적 인터페이스

인터페이스 변수 = 람다식 

14.3.1 함수적 인터페이스@FunctionalInteface)

하나의 추상 메소드가 선언된 인터페이스만이 람다식의 타켓 타입이 될수 있는데 , 이러한 인터페이스를 함수적 인터페이스라고 한다.

14.3.2 매개변수와 리턴값이 없는 람다식

14.3.3 매개 변수가 있는 람다식

14.3.4 리턴값이 있는 람다식

 

14.4 클래스 멤버와 로컬 변수 사용

클래스의 멤버는 제약 사항 없이 사용가능하지만 ,로컬 변수는 제약 사향이 따른다.

14.4.1 클래스의 멤버 사용

this는 내부적으로 생성되는 익명 객체의 참조가 아니라 람다식을 실행한 객체의 참조이다.

14.4.2 로컬 변수 사용

final특성 

 

 

14.5 표준 api의 함수적 인터페이스

14.5.1 Consumer함수적 인터페이스

14.5.2 Supplier 함수적 인터페이스

14.5.3  Function 함수적 인터페이스

14.5.4 Operator함수적 인터페이스

14.5.5 Predicate함수적 인터페이스

14.5.6 andThen()과 compose()디폴드 메소드

andThen()과 compose() 차이점은 어떤 함수적 인터페이스부터 먼저 처리하느냐이다.

14.5.7 and(),or(), negate()디폴트 메소드와 isEqual()정적 메소드

14.5.8 minBy(),maxBy()정적 메소드

 

14.6 메소드 참조

메소드 참조 method References는 말 그대로 메소드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내어 ,람다식에서 불필요한 매개 변수를 제거하는 것이 목적이다.

람다식은 종종 기존 메소드를 단순히 호출만 하는 경우가 많다.

14.6.1 정적 메소드와 인스턴스 메소드 참조

static

14.6.2 매개변수의 메소드 참조

14.6.3 생성자 참조

메소드 참조 (method references)는 생성자 참조도 포함한다. 

생성자를 참조한다는 것은 객체 생성을 의미한다.

 



 

13.3 멀티 타입 파라미터(class<K,V,...>, interface<K,V

,...>)

반응형

' > 이것이 자바다' 카테고리의 다른 글

16. 스프림과 병렬 처리  (0) 2020.10.17
15. 컬렉션 프레임워크  (0) 2020.10.13
12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
10. 예외처리  (0) 2020.10.01
반응형

출처 : 이것이 자바다 

멀티 스레드

12.1. 멀티 스레드 개념

12.1.1 프로세스와 스레드

운영체제에서는 실행 중인 하나의 애플리케이션을 프로세스(process) 라고 부른다. 사용자가 애플리케이션을 실행하면 운영체제로부터 실행에 필요한 메모리를 할당받아 애플리케이션의 코드를 실행하는데 이것이 프로세스이다.

 

멀티 태스킹 (multi tasking)은 두 가지 이상의 작업을 동시에 처리하는 것을 말하는데, 운영체제는 멀티 태스킹을 할 수 있도록 CPU 및 메모리 자원을 프로세스마다 적절히 할당해주고, 병렬로 실행시킨다.

 

12.1.2 메인 스레드

모든 자바 프로그램은 메인 스레드가 (main thread) 메소드 실행하며 시작된다.

메인 스레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실행하고,main()메소드의 마지막 코드 실행하거나 return 문을 만나면 실행이 종료된다.

 

메인 스레드는 작업 스레드들을 만들어 병렬로 코드들 실행할수 있다. 즉 멀티 스레드 생성해 멀티 태스킹 수행한다.

 

프로세스의 종료

싱글 스레드: 메인 스레드가 종료하면 프로세스도 종료

멀티 스레드: 실행 중인 스레드가 하나라도 있다면, 프로세스 미종료

 

12.2 작업 스레드 생성과 실행

 java.lang.Thread 클래스를 직접 객체화해서 생성해도 되지만, Thread를 상속해서 하위 클래스를 만들어 생성할 수도 있다.

 

12.2.1 Thread 클래스로부터 직접 생성

Runnable은 작업 스레드가 실행할 수 있는 코드를 가지고 있는 객체라고 해서 붙여진 이름이다.

Runnable은 인터페이스 타입이기 때문에 구현 객체를 만들어 대입해야 한다.

Runnable에는 run() 메소드 하나가 정의되어 있는데, 구현 클래스는 run()을 재정의해서 작업 스레드가 실행할 코드를 작성해야 한다. 

class Task implements Runnable {
  public void run() {
  	스레드가 실행할 코드;
  }
}

Runnable 인터페이스는 run() 메소드 하나만 정의되어 있기 때문에 함수적 인터페이스이다.

Thread thread = new Thread( () -> {
	스레드가 실행할 코드;
});
thread.start();

read.strt();

import java.awt.*;
 
public class BeepPrintExample1 {    //메인 스레드만 이용한 경우
 
    public static void main(String[] args) {
        Toolkit toolkit = Toolkit.getDefaultToolkit();         //Toolkit 객체 얻기
        for (int i = 0; i<5; i++) {
            toolkit.beep();                                    //비프음 발생
            try { Thread.sleep(500); } catch (Exception e) {} //0.5초간 일시정지
        }
        
        for (int i = 0; i <5; i++) {
            System.out.println("띵");
            try { Thread.sleep(500); } catch (Exception e) { //0.5초간 일시정지
            }
        }
    }
 
}

비프음 발생시키면서 동시에 프린팅을 하려면 두 작업 중 하나를 메인 스레드가 아닌 다른 스레드에서 실행시켜야 한다.

프린팅은 메인 스레드가 담당하고 비프음을 들려주는 것은 작업 스레드가 담당하도록 수정해보자.우선 작업을 정의하는 Runnable 구현 클래스를 다음과 같이 작성한다.

 

public class BeepTask implements Runnable{
    @Override
    public void run() {
        Toolkit toolkit = Toolkit.getDefaultToolkit();         
        for (int i = 0; i<5; i++) {
            toolkit.beep();                                    
            try { Thread.sleep(500); } catch (Exception e) {} 
        }
    }
}
public class BeepPrintExample2 {
 
    public static void main(String[] args) {
        Runnable beepTask = new BeepTask();
        Thread thread = new Thread(beepTask);
        thread.start();
        
        for (int i = 0; i <5; i++) {
            System.out.println("띵");
            try { Thread.sleep(500); } catch (Exception e) {} //0.5초간 일시정지
        }
    }
}

12.2.2 Thread 하위 클래스로부터 생성

다음은 작업 스레드 클래스를 정의하는 방법인데, Thread 클래스를 상속한 후 run 메소드를 재정의(overriding) 해서 스레드가 실행할 코드를 작성하면 된다.

Thread thread = new Thread() {
  public void run() {
  	스레드가 실행할 코드;
  }
};
import java.awt.Toolkit;
 
public class BeepThread extends Thread{
    @Override
    public void run() {
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    for(int i=0; i<5; i++) {
        toolkit.beep();
        try {Thread.sleep(500);} catch (Exception e) {}
        }
    }
}
public class BeepPrintExample3 {
    public static void main(String[] args) {
        Thread thread = new BeepThread();
        thread.start();
        
        for(int i=0;i<5;i++) {
            System.out.println("띵");
            try { Thread.sleep(500); }
            catch (Exception e) {}
        }
    }
}

12.2.3 스레드의 이름

thread.setName("스레드 이름");

public class ThreadNameExample {
 
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();        
        System.out.println("프로그램 시작 스레드 이름: " + mainThread.getName());
        
        ThreadA threadA = new ThreadA();   
        System.out.println("작업 스레드 이름:" + threadA.getName());
        threadA.start();
        
        ThreadB threadB = new ThreadB();
        System.out.println("작업 스레드 이름:" + threadB.getName());
        threadB.start();
    }
}
public class ThreadA extends Thread{
    public ThreadA() {
        setName("ThreadA");       
    }
    
    @Override
    public void run() {        
        for(int i=0; i<2; i++) {        
            System.out.println(getName() + "가 출력한 내용");       
        }
    }
}

thread.stNam

public class ThreadB extends Thread{
    @Override
    public void run() {   
        for(int i=0;i<2;i++) {
            System.out.println(getName() + "가 출력한 내용");
        }
    }
}

 

12.3 스레드 우선순위

멀티 스레드는 동시성(Concurrency) 또는 병렬성(Parallelism) 으로 실행되기 때문에 이 용어들에 대해 정확히 이해하는 것이 좋다.동시성은 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행하는 성질을 말하고 , 병렬성은 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질을 말한다. 

 

스레드의 개수가 코어의 수 보다 많을 경우, 스레드를 어떤 순서에 의해 동시성으로 실행할 것인가를 결정해야 하는데, 이것을 스레드 스케줄링이라고 한다. 스레드 스케줄링에 의해 스레드들은 아주 짧은 시간에 번갈아가면서 그들의 run() 메소드를 조금씩 실행한다.

 

자바의 스레드 스케줄링은 우선순위(Priority) 방식과 순환 할당(Round-Robin) 방식을 사용한다.우선순위 방식은 우선순위가 높은 스레드가 실행 상태를 더 많이 가지도록 스케줄링하는 것을 말한다. 순환 할당 방식은 시간 할당량(Time Slice)을 정해서 하나의 스레드를 정해진 시간만큼 실행하고 다시 다른 스레드를 실행하는 방식을 말한다. 

 

우선순위 방식에서 우선순위 방식은 우선순위는 1에서부터 10까지 부여되는데 , 1이 가장 우선순위가 낮고 10이 가장 높다.defualt=5

 

만약 우선순위를 변경하고 싶다면 Thread 클래스가 제공하는 setPriority() 메소드를 이용하면 된다.

thread.setPriority(우선순위);

 

thread.setPriorty(Thread.MAX_PRIORITY);
thread.setPriorty(Thread.NORM_PRIORITY);
thread.setPriorty(Thread.MIN_PRIORITY);
public class CalcThread extends Thread{
    public CalcThread(String name) {
        setName(name);   
    }
    
    public void run() {   
        for(int i=0;i<2000000000; i++) {
        }            
        System.out.println(getName());
    }
}
public class PriorityExample {
 
    public static void main(String[] args) {
        for(int i=1;i<=10;i++) {
            Thread thread = new CalcThread("thread" + i);
            if(i==10) {
                thread.setPriority(Thread.MAX_PRIORITY);
            } else {
                thread.setPriority(Thread.MIN_PRIORITY);
            }
            thread.start();
        }
    }
 
}

12.4 동기화 메소드와 동기화 블록

12.4.1 공유 객체를 사용할 때의 주의할 점

싱글 스레드 프로그램에서는 한 개의 스레드가 객체를 독차지해서 사용하면 되지만, 멀티 스레드 프로그램에서는 스레드들이 객체를 공유해서 작업해야 하는 경우가 있다.

public class MainThreadExample {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        
        User1 user1 = new User1();
        user1.setCalculator(calculator);   
        user1.start();
        
        User2 user2 = new User2();
        user2.setCalculator(calculator);
        user2.start();
    }
}
public class Calculator {
    private int memory;
    
    public int getMemory() {
        return memory;
    }
    
    public void setMemory(int memory) {   
        this.memory = memory;    
        try {   
            Thread.sleep(2000);
        } catch (InterruptedException e) {}
            System.out.println(Thread.currentThread().getName() + ": " + this.memory);
    }
}
public class User1 extends Thread {
    private Calculator calculator;
    
    public void setCalculator(Calculator calculator) {
        this.setName("User1"); 
        this.calculator = calculator; 
    }
    
    public void run() {
        calculator.setMemory(100);
    }
}
 

e("스레드 이름"

public class User2 extends Thread{
    private Calculator calculator;
    
    public void setCalculator(Calculator calculator) {
        this.setName("User2");        
        this.calculator = calculator;    
    }
    
    public void run() {
        calculator.setMemory(50);   
    }
}

12.4.2 동기화 메소드 및 동기화 블록

멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역을 임계 영역(critical section)이라고 한다.

자바는 임계 영역을 지정하기 위해 동기화(synchronized) 메소드와 동기화 블록을 제공한다.

public synchronized void method() {
	임계 영역; //단 하나의 스레드만 실행
}

); 으로 변경 가능thr

public void method() {
  //여러 스레드가 실행 가능 영역
  synchronized(공유객체) {
  	임계 영역 // 단 하나의 스레드만 실행
  }
  //여러 스레드가 실행 가능 영역
}

ead.setName("

public class Calculator {
 private int memory;

 public int getMemory() {
  return memory;
 }

 public synchronized void setMemory(int memory) { 
  this.memory = memory;
  try {
   Thread.sleep(2000);
  } catch(InterruptedException e) {} 
  System.out.println(Thread.currentThread().getName() + ": " +  this.memory);
 }
}
public void setMemory(int memory) {
	synchronized(this){
		this.memory = memory;
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){ }
        System.out.println(Thread.currentThread().getName() + ": " +  this.memory + "저장");
    }
}

12.5 스레드(Thread) 상태

스레드의 일반적인 상태

일시 정지 상태는 WAITING, TIMED_WAITING, BLOCKED 가 있습니다. 

public class StatePrintThread extends Thread { 

 private Thread targetThread;
 
 public StatePrintThread(Thread targetThread) { // 상태를 조사할 스레드
  this.targetThread = targetThread;
 }

 public void run() {
  while(true) {
   Thread.State state = targetThread.getState(); //스레드 상태 얻기
   System.out.println("타겟 스레드 상태: " + state);

   if(state == Thread.State.NEW) {//객체 새성 상태일 경우, 실행 대기 상태로 만듬
    targetThread.start(); 
   }
   
   if(state == Thread.State.TERMINATED) { //종료 상태일 경우 while문을 종료
    break; 
   }
   try {
    //0.5초간 일시 정지듬
    Thread.sleep(500);
   } catch(Exception e) {}
  }
 }
}

12.스레드 이름"); 11225.으로 변경

public class TargetThread extends Thread { 
 public void run() {
  for(long i=0; i<1000000000; i++) {}
  
  try {
   //1.5초간 일시 정지
   Thread.sleep(1500);
  } catch(Exception e) {}

  for(long i=0; i<1000000000; i++) {}
 }
}

public class ThreadStateExample {
 public static void main(String[] args) {
  StatePrintThread statePrintThread = new StatePrintThread(new TargetThread());
  statePrintThread.start();
 }
}

12.6 스레드 상태 제어

실행 중인 스레드의 상태를 변경하는 것을 스레드 상태 제어라고 한다.

 

12.6.1 주어진 시간동안 일시 정지 sleep()

try{
   Thread.sleep(1000);
}catch(InterruptedException e){
  //interrupt() 메서드가 호출되면 실행
}

12thread.setN1

import java.awt.Toolkit;

public class SleepExample {
 public static void main(String[] args) {
  Toolkit toolkit = Toolkit.getDefaultToolkit();  
  for(int i=0; i<10; i++) {
   toolkit.beep();
   try {
    Thread.sleep(1500); // 1.5초동안 메인 스레드를 일시 정지 상태로 만듭니다
   } catch(InterruptedException e) {   
   }  
  } 
 }
}

12.6.2 다른 스레드에게 실행 양보 yield() 

public void run() {
	while(true) {
    	if(work) {
            System.out.println("Thread1 작업 내용");
		}
	}
}

스레드가 시작되어 run() 메서드를 실행하면 while(true) {} 블록이 무한 루프를 돌게 됩니다.  만약 work의 값이 false 라면 그리고 work 값이 false 에서 true로 변경되는 시점이 불분명하다면,  while문은 어떤한 실행문도 실행하지 않고 무의미한 반복을 한다.

public void run() {
   while(true) {
        if(work) {
            System.out.println("Thread1 작업 내용");
        } else {
            Thread.yield();
        }
   }
}

12.6.3 다른 스레드의 종료를 기다림 join()

public class SumThread extends Thread { 
 private long sum;

 public long getSum() {
  return sum;
 }

 public void setSum(long sum) {
  this.sum = sum;
 }

 public void run() {
  for(int i=1; i<=100; i++) {
   sum+=i;
  }
 }
}
public class JoinExample {
 public static void main(String[] args) {
  SumThread sumThread = new SumThread();
  sumThread.start();
  try {
   sumThread.join();
  } catch (InterruptedException e) {
  }
  
  System.out.println("1~100 합: " + sumThread.getSum());

 }

}

12.6.4 스레드 간 협업 wait(), notify(), notifyAll()

public class WorkObject {
 public synchronized void methodA() {
  System.out.println("ThreadA의 methodA() 작업 실행");
  notify();//일시정지상태에 있는 ThreadB를 실행대기상태로 만듬
  try {
   wait();//ThreadA를 일시 정지 상태로 만듬
  } catch (InterruptedException e) {
  }
 }
 
 public synchronized void methodB() {
  System.out.println("ThreadB의 methodB() 작업 실행");
  notify();//일시정지상태에 있는 ThreadA를 실행대기상태로 만듬
  try {
   wait();//ThreadB를 일시 정지 상태로 만듬
  } catch (InterruptedException e) {
  }
 }
}

11ame("1스

public class ThreadA extends Thread {

 private WorkObject workObject;

 public ThreadA(WorkObject workObject) {
  this.workObject = workObject; // 공유 객체를 매개값으로 받아 필드에 저장
 }

 @Override
 public void run() {
  for(int i=0; i<10; i++) {
   workObject.methodA();
  }//공유 객체의 methodA()를 10번 반복
 }
}

12.111111

public class ThreadB extends Thread {
 private WorkObject workObject;

 public ThreadB(WorkObject workObject) {
  this.workObject = workObject;// 공유 객체를 매개값으로 받아 필드에 저장
 }

 @Override
 public void run() {
  for(int i=0; i<10; i++) {
   workObject.methodB();
  }//공유 객체의 methodB()를 10번 반복
 }
}

thread.

public class WaitNotifyExample {
 public static void main(String[] args) {
  WorkObject sharedObject = new WorkObject(); // 겅우 객체 생성
  ThreadA threadA = new ThreadA(sharedObject);
  ThreadB threadB = new ThreadB(sharedObject);
  threadA.start();
  threadB.start(); 스래드 A,B 실행
 }
}

12.6.5 스레드의 안전한 종료 stop플래그, interrupt()

스레드는 자신의 run() 메서드가 모두 실행되면 자동적으로 종료된다. 

 

스레드의 안전한 종료 stop플래그, interrupt()

 스레드는 자신의 run() 메서드가 모두 실행되면 자동적으로 종료됩니다.

경우에 따라 실행 중인 스레드를 즉시 종료할 필요가 생길 수 있습니다. 

예를 들면 동영상을 끝까지 보지 않고 사용자가 멈춤을 요구할 경우가  있을 수 있습니다. 

Thread는 스레드를 즉시 종료시키기 위해 stop()메서드를 제공하지만 

이 메서드는 Deprecated되어있습니다. 

 =>아래 두가지 방법은 스레드를 즉시 종료시키기 위한 최선의 방법입니다.

 

stop 플래그를 이용하는 방법

public class XXXThread extends Thread {
     private boolean stop; // stop 플래그 필드
     public void run() {
        while(!stop){ stop가 true가 되면 run() 종료
           스레드가 반복 실행하는 코드;
        }
       //스레드가 사용한 자원 정리
   }
}

setN112.2a

public class StopFlagExample {
 public static void main(String[] args)  {
  PrintThread1 printThread = new PrintThread1();
  printThread.start();
  try {
   Thread.sleep(1000);
  } catch (InterruptedException e) {
  }

  printThread.setStop(true);
 }
}

d.setName("스레드 이름"); 으로 변경 가

public class PrintThread1 extends Thread {
 private boolean stop;

 public void setStop(boolean stop) {
   this.stop = stop;
 }

 public void run() { 
  while(!stop) {
   System.out.println("실행 중");
  } 

  System.out.println("자원 정리");
  System.out.println("실행 종료");
 }
}

interrupt() 메서드를 이용하는 방법

public class InterruptExample {

 public static void main(String[] args)  {

  Thread thread = new PrintThread2();
  thread.start();
  try {
   Thread.sleep(1000);
  } catch (InterruptedException e) {
  }

  thread.interrupt();
 }
}
public class PrintThread2 extends Thread {
 public void run() { 
  try {
   while(true) {
    System.out.println("실행 중");
    Thread.sleep(1);
   } 
  } catch(InterruptedException e) {  
  }  

  System.out.println("자원 정리");
  System.out.println("실행 종료");
 }
}

12.7 데몬 스레드

데몬(daemon) 주 스레드의 작업 돕는 보조적인 역할 수행하는 스레드이다.

현재 실행 중인 스레드가 데몬 스레드인지 아닌지 구별하는 방법은 isDaemon()메소드의 리턴값을 조사해보면 된다.

public class AutoSaveThread extends Thread {
 public void save() {
  System.out.println("작업 내용을 저장함.");
 }

 @Override
 public void run() {
  while(true) {
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    break;
   }
   save(); // 1초 주기로 save()메서드 호출
  }
 }
}
public class DaemonExample {
 public static void main(String[] args) {
  AutoSaveThread autoSaveThread = new AutoSaveThread();
  autoSaveThread.setDaemon(true); // 데몬스레드로 만들기
  autoSaveThread.start();
  try {
   Thread.sleep(3000); // 메인 스레드가 종료되면 데몬 스레드도 같이 종료
  } catch (InterruptedException e) {
  }
  System.out.println("메인 스레드 종료");
 }
}

12.8 스레드 그룹

관련된 스레드를 묶어서 관리할 목적으로 이용된다.

 

12.8.1 스레드 그룹 이름 얻기

public class ThreadInfoExample {

 public static void main(String[] args) {
  AutoSaveThread autoSaveThread = new AutoSaveThread();
  autoSaveThread.setName("AutoSaveThread");
  autoSaveThread.setDaemon(true);
  autoSaveThread.start();
  Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
  Set<Thread> threads = map.keySet(); 
  
  for(Thread thread : threads) {
   System.out.println("Name: " + thread.getName() + ((thread.isDaemon())?"(데몬)": "(주)"));
   System.out.println("\t" + "소속그룹: " + thread.getThreadGroup().getName());
   System.out.println();
  }
 }
}

12.8.2 스레드 그룹 생성

Thread t = new Thread(ThreadGroup group, Runnable target);
Thread t = new Thread(ThreadGroup group, Runnable target, String name);
Thread t = new Thread(ThreadGroup group, Runnable target, String name, long stackSize);
Thread t = new Thread(ThreadGroup group, String name);

12.8.3 스레드 그룹의 일괄 interrupt()

스레드 그룹에서 제공하는 interrupt() 메서드를 이용하면 그룹 내에 포함된 모든 스레드들을 일괄 interrupt()할 수 있다.

public class WorkThread extends Thread {

 public WorkThread(ThreadGroup threadGroup, String threadName) {
  super(threadGroup, threadName);
 }

 @Override
 public void run() {
  while(true) {
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    System.out.println(getName() + " interrupted");
    break;
   }
  }
  System.out.println(getName() + " 종료됨");
 }
}
public class ThreadGroupExample {

 public static void main(String[] args) {
  ThreadGroup myGroup = new ThreadGroup("myGroup");
  WorkThread workThreadA = new WorkThread(myGroup, "workThreadA");
  WorkThread workThreadB = new WorkThread(myGroup, "workThreadB");

  workThreadA.start();
  workThreadB.start();

  System.out.println("[ main 스레드 그룹의 list() 메소드 출력 내용 ]");
  ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();  
  mainGroup.list();
  System.out.println();

  try {
   Thread.sleep(3000);
  } catch (InterruptedException e) {
  }

  System.out.println("[ myGroup 스레드 그룹의 interrupt() 메소드 호출 ]");
  myGroup.interrupt();
 }
}

12.9 스레드풀

스레드 폭증으로 일어나는 현상

병렬 작업 처리가 많아지면 스레드 개수 증가

스레드 생성과 스케줄링으로 인해 CPU바빠짐

메모리 사용량이 늘어남

애플리케이션의 성능 급격히 저하

 

스레드 풀(Thread Pool)

작업 처리에 사용되는 스레드를 제한된 개수만큼 미리 생성

작업 큐(Queue)에 들어오는 작업들을 하나씩 스레드가 맡아 처리

작업 처리가 끝난 스레드는 작업 결과를 애플리케이션으로 전달

스레드는 다시 작업 큐에서 새로운 작업을 가져와 처리

 

12.9.1 스레드풀 생성 및 종료

스레드풀 생성

ExecutorService 구현 객체는 Executors Class의  두 메소드 중 하나를 이용해서 간편하게 생성할 수 있다.

ExecutorService threadPool= new ThreadPoolExecutor (

     3, // 코어 스레드 수

     100, // 최대 스래드 수

     120L, // 놀고 있는 시간

     TimeUnit.SECONDS, // 놀고 있는 시간 단위

     new SynchronousQueue<Runnable>() // 작업 큐

)

 

12.9.2 작업 생성과 처리 요청

작업 생성 

작업 처리 요청

execute()

스레드 종료 후 해당 스레드 제거

스레드 풀은 다른 작업 처리를 위해 새로운 스레드 생성

submit()

스레드가 종료되지 않고 다음 작업 위해 재사용

 

12.9.3 블로킹 방식의 작업 완료 통보 받기

Future 객체

작업 결과가 아니라 지연 완료(pending completion) 객체

작업이 완료될까지 기다렸다가 최종 결과를 얻기 위해 get() 메소드 사용

UI 변경과 같은 스레드에 사용 불가 

 

12.9.4 콜 백 방식의 작업 완료 통보 받기

콜백이란 애플리케이션이 스레드에게 작업 처리를 요청한 후, 스레드가 작업을 완료하면 특정 메소드를 자동 실행하는 기법을 말한다.

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

15. 컬렉션 프레임워크  (0) 2020.10.13
13. 제네릭 14. 람다식  (0) 2020.10.10
11. 기본 API 클래스  (0) 2020.10.02
10. 예외처리  (0) 2020.10.01
09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
반응형

출처 : 이것이 자바다

기본 API 클래스

11.1 자바 API 도큐먼트

자바 API?

자바에서 기본적으로 제공하는 라이브러리(library)

 

프로그램 개발에 자주 사용되는 클래스 및 인터페이스 모음

PI 도큐먼트 (p.454~456)

쉽게 API 찾아 이용할 수 있도록 문서화한 것

HTML 페이지로 작성되어 있어 웹 브라우저로 바로 볼 수 있음

http://docs.oracle.com/javase/8/docs/api/

API 도큐먼트는 세 개의 프로그레임으로 나누어져 있다.

좌측 상단의 프레임에는 패키지 전체 목록을 보여주,

좌측 하단 프레임에는 패키지에 속하는 클래스와 인터페이스 목록을 보여준다.

중앙 프레임에는 좌측 화단 프레임에서 선택한 클래스나 인터페이스에 대한 설명을 보여준다.

 

중앙 프로임의 내용은 크게 세 부분으로 구분된다.

상단 부분은 클래스가 포함된 정보, 상속 정보, 인터페이스 구현 정보를 표시한다.

중앙 부분은 클래스의 설명과 사용 방법을 간략하게 보여준다.

하단 부분은 필드, 생성자 , 메소드의 목록을 보여준다.

클래스가 가지고 있는 중첩 클래스 , 필드 , 생성자 , 메소드의 목록으로 바로 가고 싶다면 상단의 Shmmary 부분에 있는 Nested|Field|Constr|Method 링크를 바로 클릭하면 된다.

 

다음은 String 클래스의 Constructor Summary 내용을 보여준다.

 

 Method Summary

 

 

11.2 java.lang java.util 패키지

공통적으로 사용하는 패키지

11.2.1 java.lang 패키지

자바 프로그램의 기본적인 클래스를 담은 패키지

포함된 클래스와 인터페이스는 import 없이 사용

주요 클래스

 

 

11.2.2 java.util패키지

클래스

용도

Arrays

-배열을 조작(비교, 복사 , 정렬, 찾기) 할 때 사용

Calendar

-운영체제의 날짜와 시간을 얻을 때 사용

Date

-날짜와 시간 정보를 저장하는 클래스

Objects

-객체 비교 , (null)여부 등을 조사할 때 사용

StringTokenizer

-특정 문자로 구분된 문자열을 뽑아날 때 삳용

Random

난수를 얻을 때 사용

11.3 Object클래스

자바의 최상위 부모 클래스

다른 클래스 상속하지 않으면 java.lang.Object 클래스 상속 암시

Object의 메소드는 모든 클래스에서 사용 가능

 

클래스를 선언할 때 다른 클래스를 상속하지 않으면 java.lang.Object 클래스를 상속하게 됩니다

따라서 자바의 모든 클래스는 Object 클래스의 자식이거나 자손 클래스입니다.

Object는 자바의 최상위 클래스에 해당합니다

 

 

api 도큐먼트에서 Object클래스를 한번 찾아보자.

 

Object클래스는 필드가 없고 , 메소드들로 구성되어 있다 . 이 메소드들은 모든 클래스가 Object를 상속하기 때문에 모든 클래스에서 사용이 가능하다.

 

public class ApiSpecificationExample {

           public static void main(String[] args) {

                       String name = "홍길동";

                       System.out.println(name);

           }

}

자바 에디터에서 클래스를 마우스로 선택한 다음 F1키를 누르면 자동으로 API 도큐먼트를 보여주는 Help뷰가 실행된다.

 

Object클래스는 필드가 없고 , 메소드들로 구성되어 있다.

 

11.3.1. 객체 비교(equals())

 

 

 

기본적으로 == 연산자와 동일한 결과 리턴 (번지 비교)

논리적 동등 위해 오버라이딩 필요

논리적 동등이란?

같은 객체이건 다른 객체이건 상관없이 객체 저장 데이터 동일

Object equals() 메소드

재정의하여 논리적 동등 비교할 때 이용

 

객체 동등 비교(equals() 메소드)

public class Member {

           public String id;

 

           public Member(String id) {

                       this.id = id;

           }

 

           @Override

            public boolean equals(Object obj) {

             if(obj instanceof Member) { //매개값이 Member 타입인지 확인

              Member member = (Member) obj; // 강제 타입 변환 후

              if(id.equals(member.id)) { // id 필드 값이 동일한지 검사한 후

               return true; // 동일하다면 true 리턴

              }

             }

             return false; //

            }

}

 

 

객체 동등 비교(equals() 메소드)

public class MemberExample {

           public static void main(String[] args) {

                       Member obj1 = new Member("blue");

                       Member obj2 = new Member("blue");

                       Member obj3 = new Member("red");

 

                       if (obj1.equals(obj2)) { // 매개값이 Member 타입이고 id 필드 값도 동일 true 리턴

                                  System.out.println("obj1 obj2는 동등함.");

                       } else {

                                  System.out.println("obj1 obj2는 동등하지 않음.");

                       }

 

                       if (obj1.equals(obj3)) { // 매개값이 Member 타입이지만 id 필드값이 다르므로 false 리턴

                                  System.out.println("obj1 obj3은 동등함.");

                       } else {

                                  System.out.println("obj1 obj3은 동등하지 않음.");

                       }

           }

}

 

 

11.3.2 객체 해시코드(hashCode)

객체 해시코드란?

객체 식별할 하나의 정수값

객체의 메모리 번지 이용해 해시코드 만들어 리턴

개별 객체는 해시코드가 모두 다름

 

논리적 동등 비교 시 hashCode() 오버라이딩의 필요성

컬렉션 프레임워크의 HashSet, HashMap, Hashtable 과 같은 클래스는 두 객체가 동등한 객체인지 판단할 때 아래와 같은 과정을 거침

 

 

 

 

 

 

hashCode()메소드를 재정의 하지 않음

public class Key {

           public int number;

            

            public Key(int number) {

             this.number = number;

            }

            

            @Override

            public boolean equals(Object obj) {

             if(obj instanceof Key) {

              Key compareKey = (Key) obj;

              if(this.number == compareKey.number) {

               return true;

              }

             }

             return false;

            }

}

 

이런 경우 HashMap 의 식별키로 Key 객체를 사용하면 저장된 값을 찾아오지 못합니다

이유는 number 필드값이 같더라도 hashCode() 메서드에서 리턴하는 해시코드가 다르기 때문에 

다른 식별키로 인식하기 때문입니다. 아래 실행 예제를 보겠습니다.

 

다른 키로 인식

hashCode() 메소드 재정의 추가

 

다른 키로 인식

public class KeyExample {

           public static void main(String[] args) {

                       // Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성

                       HashMap<Key, String> hashMap = new HashMap<Key, String>();

 

                       // 1.식별키 "new Key(1)" "네이버"을 저장함

                       hashMap.put(new Key(1), "네이버");

 

                       // 2.식별키 "new Key(1)" "네이버"을 읽어옴

                       String value = hashMap.get(new Key(1));

                       System.out.println(value);

 

                       Object obj = new Object();

                       System.out.println(obj);

                       System.out.println(obj.hashCode()); // 3.하지만 결과값은 null이 나옵니다.

           }

}

 

의도한 대로 "네이버"를 읽으려면 아래와 같이 재정의한 hashCode() 메서드를 Key 클래스에 추가하면 됩니다.
public class Key {

           public int number;

 

           public Key(int number) {

                       this.number = number;

           }

 

           @Override

           public boolean equals(Object obj) {

                       if (obj instanceof Key) {

                                  Key compareKey = (Key) obj;

                                  if (this.number == compareKey.number) {

                                              return true;

                                  }

                       }

                       return false;

           }

          

           @Override

           public int hashCode() {

                       return number;

           }

}

 

객체의 동등 비교를 위해서는 Objectequals() 메소드만 재정의하지 말고 hashCode()메소드 재정의 해서 논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야 한다.

 

hashCode() 메소드 재정의 추가

public class Member {

           public String id;

 

           public Member(String id) {

                       this.id = id;

           }

 

           @Override

           public boolean equals(Object obj) {

                       if (obj instanceof Member) { // 매개값이 Member 타입인지 확인

                                  Member member = (Member) obj; // 강제 타입 변환 후

                                  if (id.equals(member.id)) { // id 필드 값이 동일한지 검사한 후

                                              return true; // 동일하다면 true 리턴

                                  }

                       }

                       return false; //

           }

          

           @Override

           //id가 동일한 문자열은 경우 같은 해시코드를 리턴

           public int hashCode() {

                       return id.hashCode();

           }

}

 

11.3.3 객체 문자 정보(toString())

 

객체를 문자열로 표현한 값

Object 클래스의toString() 메소드는 객체의 문자 정보 리턴

 

 

 

일반적으로 의미 있는 문자정보가 나오도록 재정의

Date 클래스- 현재 시스템의 날짜와 시간 정보 리턴

String 클래스 - 저장하고 있는 문자열 리턴

 

System.out.pritnln(Object) 메소드

Object toString()의 리턴값 출력

 

Object 클래스의 toString() 메서드의 리턴값은 자바 애플리케이션에서는 별로 중요하지 않은 정보이므로

 Object 하위 클래스는 toString() 매서드를 오버라이딩해서 간결하고 유익한 정보를 리턴하도록 되어 있습니다.

 예를 들어 java.util 패키지의 Date 클래스는

 toString() 메서드를 오버라이딩하여 현재 시스템의 날짜와 시간 정보를 리턴합

 

객체의 문자 정보(toString() 메소드)

public class ToStringExample {

           public static void main(String[] args) {

                       Object obj1 = new Object();

                       Date obj2 = new Date();

                       System.out.println(obj1.toString());

                       System.out.println(obj2.toString());

           }

}

 

 

객체의 문자 정보(toString()메소드)

public class SmartPhone {

           private String company;

           private String os;

 

           public SmartPhone(String company, String os) {

                       this.company = company;

                       this.os = os;

           }

 

           @Override

 

           public String toString() {

                       return company + ", " + os;

           }

 

}

 

객체의 문자 정보(toString()메소드)

public class SmartPhoneExample {

           public static void main(String[] args) {

 

                       SmartPhone myPhone = new SmartPhone("구글", "안드로이드");

                       String strObj = myPhone.toString();

                       System.out.println(strObj);

                       System.out.println(myPhone);

           }

}

 

 

113.4 객체 복제(clone)

v  객체 복제(clone())

원본 객체의 필드 값과 동일한 값을 가지는 새로운 객체 생성하는 것

복제 종류

      얕은 복제(thin clone): 필드 값만 복제 (참조 타입 필드는 번지 공유)

      깊은 복제(deep clone): 참조하고 있는 객체도 복제

 

 

 

 

 

 

 

    • Object clone() 메소드

      동일한 필드 값 을 가진 얕은 복제된 객체 리턴

      java.lang.Cloneable 인터페이스 구현한 객체만 복제 가능

    • 깊은 복제 -  clone() 메소드 재정의하고 참조 객체도 복제해야

얕은 복제(thin clone)

필드 값을 복사해서 객체를 복제하는 것. 필드값만 복제하기 때문에 

필드가 기본 타입일 경우 값 복사가 일어나고 필드가 참조 타입일 경우에는 객체의 번지가 복사됩니다

)원래 객체에 int 타입의 필드와 배열 타입의 필드가 있을 경우 얕은 복제된 필드의 값은 아래 그림과 같습니다.

 

clone() 메서드는 자신과 동일한 필드값을 가진 얕은 복제된 객체를 리턴합니다

clone() 메서드로 객체를 복제하려면 반드시 원본 객체는 Cloneable 인터페이스를 구현 해야함

메서드 선언이 없음에도 Cloneable 인터페이스를 명시적으로 구현하는 이유 :

클래스의 설계자가 복제를 허용한다는 의도적 표현을 하기 위해

설계자가 복제를 허용하지 않는다면 Cloneable 인터페이스를 구현하지 않으면 됩니다

Cloneable 인터페이스를 구현하지 않는다면 clone() 메서드를 호출할 때 CloneNotSupportedException 예외가 발생

clone() CloneNotSupportedException 예외처리가 필요한 메소드라서 try - catch 문이 필요합니다.

try{

   Object o = clone();

}catch(CloneNotSupportedException e) { }

 

복제할 수 있는 클래스 선언

package textbook.chapter11.exam01;

 

public class Member implements Cloneable {

           public String id; // 복제할 수 있다는 뜻이겠죠?

           public String name;

           public String password;

           public int age;

           public boolean adult;

 

           public Member(String id, String name, String password, int age, boolean adult) {

                       this.id = id;

                       this.name = name;

                       this.password = password;

                       this.age = age;

                       this.adult = adult;

           }

 

           public Member getMember() {

                       Member cloned = null;

                       try {

                                  cloned = (Member) clone(); // clone() 메서드의 리턴타입이 Object이므로 Member 타입으로 캐스팅해야 합니다.

                       } catch (CloneNotSupportedException e) {

                                  e.printStackTrace();

                       }

                       return cloned;

           }

}


실행 클래스

public class MemberExample {

           public static void main(String[] args) {

                       // 원본 객체 생성

                       Member original = new Member(" yellow", "부르곰", "12345", 25, true);

 

                       // 복제 객체를 얻은 후에 패스워드 변경

                       Member cloned = original.getMember(); // 복제 객체

                       cloned.password = "67890"; // 복제 객체의 비밀번호 변경

 

                       System.out.println("[복제 객체의 필드값]");

                       System.out.println("id: " + cloned.id);

                       System.out.println("name: " + cloned.name);

                       System.out.println("password: " + cloned.password);

                       System.out.println("age: " + cloned.age);

                       System.out.println("adult: " + cloned.adult);

                       System.out.println();

 

                       System.out.println("[원본 객체의 필드값]");

                       System.out.println("id: " + original.id);

                       System.out.println("name: " + original.name);

                       System.out.println("password: " + original.password);// 하지만 원본 객체의 비밀번호 는 변함이 없죠~

                       System.out.println("age: " + original.age);

                       System.out.println("adult: " + original.adult);

           }

}

 

깊은 복제(deep clone)

얕은 복제의 단점복제 객체에서 참조 객체를 변경하려면 원본 객체도 같이 변경됩니다

깊은 복제는 참조하고 있는 객체도 복제하는 것을 말합니다

 

깊은 복제를 하려면 Object clone() 메서드를 오버라이딩해서 

참조 객체를 복제하는 코드를 직접 작성해야 해요.

 

clone()을 재정의해서 깊은 복제로 변경

package textbook.chapter11.exam02;

 

import java.util.Arrays;

 

public class Member implements Cloneable {

           public String name;

           public int age;

           public int[] scores; // 참조 타입 필드

           public Car car; // 깊은 복제 대상

 

           public Member(String name, int age, int[] scores, Car car) {

                       this.name = name;

                       this.age = age;

                       this.scores = scores;

                       this.car = car;

           }

 

           @Override // clone() 메서드 재정의

 

           protected Object clone() throws CloneNotSupportedException {

 

                       // 먼저 얕은 복사를 해서 name, age를 복제한다.

                       Member cloned = (Member) super.clone();// Object clone() 호출

                       // scores를 복제한다.

                       cloned.scores = Arrays.copyOf(this.scores, this.scores.length);

                       // car를 복제한다.

                       cloned.car = new Car(this.car.model);

                       // 깊은 복제된 Member 객체를 리턴

                       return cloned;

           }

 

           public Member getMember() {

                       Member cloned = null;

                       try {

                                  cloned = (Member) clone(); // 재정의된 clnoe() 메서드 호출

                       } catch (CloneNotSupportedException e) {

                                  e.printStackTrace();

                       }

                       return cloned;

           }

}

Car
클래스

package textbook.chapter11.exam02;

 

public class Car {

           public String model;

 

           public Car(String model) {

                       this.model = model;

           }

}

 

깊은 복제 후 복제본 변경은 원본에 영향을 미치지 않는다.

package textbook.chapter11.exam02;

 

public class MemberExample {

           public static void main(String[] args) {

                       // 원본 객체 생성

                       Member original = new Member("홍길동", 25, new int[] { 90, 90 }, new Car("소나타"));

 

                       // 복제 객체를 얻은 후에 참조 객체의 값을 변경

                       Member cloned = original.getMember();

                       cloned.scores[0] = 100;

                       cloned.car.model = "그랜저";

 

                       System.out.println("[복제 객체의 필드값]");

                       System.out.println("name: " + cloned.name);

                       System.out.println("age: " + cloned.age);

                       System.out.print("scores: {");

                       for (int i = 0; i < cloned.scores.length; i++) {

                                  System.out.print(cloned.scores[i]);

                                  System.out.print((i == (cloned.scores.length - 1)) ? "" : ",");

                       }

                       System.out.println("}");

                       System.out.println("car: " + cloned.car.model);

 

                       System.out.println();

 

                       System.out.println("[원본 객체의 필드값]");

                       System.out.println("name: " + original.name);

                       System.out.println("age: " + original.age);

                       System.out.print("scores: {");

                       for (int i = 0; i < original.scores.length; i++) {

                                  System.out.print(original.scores[i]);

                                  System.out.print((i == (original.scores.length - 1)) ? "" : ",");

                       }

                       System.out.println("}");

                       System.out.println("car: " + original.car.model);

           }

}

 

 

 

11.3.5 객체 소멸자(finalize())

    • GC는 객체를 소멸하기 직전 객체 소멸자(finalize()) 실행
    • Objectfinalize() 는 기본적으로 실행 내용이 없음
    • 객체가 소멸되기 전에 실행할 코드가 있다면?

      Object finalize() 재정의

 

    • 될 수 있으면 소멸자는 사용하지 말 것

      GC는 메모리의 모든 쓰레기 객체를 소멸하지 않음

      GC의 구동 시점이 일정하지 않음

 

참조하지 않는 배열이나 객체는 쓰레기 수집기(Garbage Collector)가 힙 영역에서 자동적으로 소멸시킨다.

쓰레기 수집기는 객체를 소멸하기 직전에 마지막으로 객체의 소멸자(finalize())를 실행시킨다.

 

참조하지 않는 배열이나 객체는 Garbage Collector 가 힙 영역에서 자동적으로 소멸시킵니다

Garbage Collector는 객체를 소멸하기 직전에 마지막으로 객체 소멸자 finalize()를 실행 시킵니다

소멸자 : Object finalize() 메서드.

기본적으로 실행 내용이 없습니다

객체가 소멸되기 전에 마지막으로 사용했던 자원(데이터 연결, 파일 등) 

닫고 싶거나 중여한 데이터를 저장하고 싶다면 Object finalize()를 재정의할 수 있습니다.


finalize()
메소드 재정의

public class Counter {

           private int no;

           public Counter(int no) {

                       this.no = no;

           }

          

           @Override

           protected void finalize() throws Throwable{

                       System.out.println(no + "번 객체의  finalize()가 실행됨");

           }

}
무작위로 소멸되는 것을 볼 수 있을 것입니다

전부 소멸되는 것이 아니라 메모리의 상태를 보고 일부만 소멸시킵니다

예제에서는 System.gc() Garbage Collector를 실행 요청했지만

Garbage Collector는 메모리가 부족할때 ,  CPU가 한가할 때에 JVM에 의해 자동적으로 실행.

finalize() 메서드가 호출된 시점은 정확하지 않습니다.프로그램이 종료될 때 즉시 자원을 해제하거나 

 데이터를 최종 저장해야 한다면 프로그램이 종료될 때 명시적으로 메서드를 호출하는 것이 좋습니다.

반복할 때마다 system.gc()를 호출해서 쓰레기 수집기를 가급적 빨리  실행해 달라고 JVM에게 요청했다.

finalize() 메소드 실행 확인

public class FinalizeExample {

           public static void main(String[] args) {

                       Counter counter = null;

                       for (int i = 1; i <= 50; i++) {

                                  counter = new Counter(i);

                                  counter = null; // counter 객체를 쓰레기로 만듭니다.

                                  System.gc(); // Garbage Collector 실행을 요청합니다.

                       }

           }

}

 

 

11.4 Objects 클래스

    • Object의 유틸리티 클래스

 

객체 비교, 해시코드 생성, null 여부, 객체 문자열 리턴 등의 연산을 수행하는 

정적 메서드들로 구성된 Object 의 유틸리티 클래스입니다

아래는 Objects 클래스가 가지고 있는 정적 메서드들입니다.

 

11.4.1 객체 비교 (Objects.compare(T a, T b, Comparator<T> c))

    • a, b 두 객체를 비교자(c)로 비교해 int값 리턴
    • Comparator<T> 인터페이스

      제너릭 인터페이스 타입

      T 타입의 객체를 비교하는 compare(T a, T b) 메소드 가짐

 

       비교 예제 p.474~476

 

두 객체를 비교자(Comparator)로 비교해서 int 값을 리턴

java.util.Comparator<T>는 두 객체를 비교하는 compare(T a, T b) 메서드가 정의되어 있습니다

T는 비교할 객체 타입이라는 것만 알아두면 되겠습니다

compare() 메서드는 리턴타입이 int 입니다

a b 보다 작으면 음수를, 같으면 0을 크면 양수를 리턴하도록 구현 클래스를 만들어야 해요.

public interface Comparator<T> {

      int compare(T a, T b)

}

 

학생 번호 비교자

class StudentComparator implements Comparator<Student> {

 

           @Override

           public int compare(Student a, Student b) {

                       if (a.ano < b.ano)

                                  return -1;

                       else if (a.ano == b.ano)

                                  return 0;

                       else

                                  return 1;

           }

 

}

 

비교자 생성

public class CompareExample {

           public static void main(String[] args) {

                       Student s1 = new Student(1);

                       Student s2 = new Student(1);

                       Student s3 = new Student(2);

 

                       int result = Objects.compare(s1, s2, new StudentComparator());

                       System.out.println(result);

 

                       result = Objects.compare(s1, s3, new StudentComparator());

                       System.out.println(result);

 

           }

 

           static class Student {

                       int sno;

                       Student(int sno) {

                                  this.sno = sno;

                       }

           }

 

           static class StudentComparator implements Comparator<Student> {

                       @Override

                       public int compare(Student a, Student b) {

                                  /*

                                   * if(a.sno<b.sno) return -1;

                                   *

                                   * else if(a.sno == b.sno) return 0;

                                   *

                                   * else return 1;

                                   */

                                  return Integer.compare(a.sno, b.sno);

                       }

           }

}

 

11.4.2 동등 비교(equals()deepEquals())

    • 두 객체의 동등 비교
    • Objects.equals(Object a, Object b)

 

    • deepEquals(Object a, Object b)

      비교할 객체가 배열일 경우 항목 값까지도 비교

 

 

객체 동등 비교

public class EqualsAndDeepEqualsExample {

           public static void main(String[] args) {

 

                       Integer o1 = 1000;

                       Integer o2 = 1000;

                       System.out.println(Objects.equals(o1, o2)); // true

                       System.out.println(Objects.equals(o1, null)); // false

                       System.out.println(Objects.equals(null, o2)); // false

                       System.out.println(Objects.equals(null, null)); // true

                       System.out.println(Objects.deepEquals(o1, o2) + "\n"); // true

 

                       Integer[] arr1 = { 1, 2 };

                       Integer[] arr2 = { 1, 2 };

                       System.out.println(Objects.equals(arr1, arr2)); // false

                       System.out.println(Objects.deepEquals(arr1, arr2)); // true

                       System.out.println(Arrays.deepEquals(arr1, arr2)); // true

                       System.out.println(Objects.deepEquals(null, arr2)); // false

                       System.out.println(Objects.deepEquals(arr1, null)); // false

                       System.out.println(Objects.deepEquals(null, null)); // true

 

           }

}

 

11.4.3해시코드 생성(hash() , hashCode())

    • Objects.hash(Object values)

      매개값으로 주어진 값들 이용해 해시 코드 생성하는 역할

      Arrays.hashCode(Object[]) 호출해 해시코드 얻어 리턴

      클래스의 hashCode()의 리턴값 생성할 때 유용하게 사용

 

    • Objects.hashCode(Object o)

      o.hashCode() 호출하고 받은 값 리턴

      매개값이 null 이면 0 리턴

 

해시코드 생성

public class EqualsAndDeepEqualsExample {

           public static void main(String[] args) {

 

                       Integer o1 = 1000;

                       Integer o2 = 1000;

                       System.out.println(Objects.equals(o1, o2)); // true

                       System.out.println(Objects.equals(o1, null)); // false

                       System.out.println(Objects.equals(null, o2)); // false

                       System.out.println(Objects.equals(null, null)); // true

                       System.out.println(Objects.deepEquals(o1, o2) + "\n"); // true

 

                       Integer[] arr1 = { 1, 2 };

                       Integer[] arr2 = { 1, 2 };

                       System.out.println(Objects.equals(arr1, arr2)); // false

                       System.out.println(Objects.deepEquals(arr1, arr2)); // true

                       System.out.println(Arrays.deepEquals(arr1, arr2)); // true

                       System.out.println(Objects.deepEquals(null, arr2)); // false

                       System.out.println(Objects.deepEquals(arr1, null)); // false

                       System.out.println(Objects.deepEquals(null, null)); // true

 

           }

}

 

11.4.4 널 여부 조사(isNull(), nonNull(), requireNonNull())

    • Objects.isNull(Object obj)

      obj null일 경우 true

    • Objects.nonNull(Object obj)

      obj not null일 경우 true

    • requireNonNull()

 

첫 번째 매개값이 not null이면 첫 번째 매개값을 리턴하고 , null이면 NullPointerException을 발생시킨다.

두 번째 매개값은 NullPointerException의 예외 메시지를 제공합니다.

 

(null) 여부 조사

public class NullExample {

           public static void main(String[] args) {

                       String str1 = "홍길동";

                       String str2 = null;

 

                       System.out.println(Objects.requireNonNull(str1));

 

                       try {

                                  String name = Objects.requireNonNull(str2);

                       } catch (Exception e) {

                                  System.out.println(e.getMessage()); // null

                       }

 

                       try {

                                  String name = Objects.requireNonNull(str2, "이름이 없습니다.");

                       } catch (Exception e) {

                                  System.out.println(e.getMessage()); // 이름이 없음.

                       }

 

                       try {

                                  String name = Objects.requireNonNull(str2,()->"이름이 없다니깐요.");

                       } catch (Exception e) { // 람다식, 뒤에서 공부하겠습니다.

                                  System.out.println(e.getMessage()); // 이름이 없음2

                       }

           }

}

 

11.4.5 객체 문자정보(toString())

    • 객체의 문자정보 리턴
    • 첫 번째 매개값이 not null - toString ( )으로 얻은 값을 리턴
    • null이면 “null” 또는 두 번째 매개값인 nullDefault 리턴

리턴 타입

메소드(매개 변수)

설명

String

toString(Object o)

not null -> o.toString()

null -> "null"

String

toString(Object o , String nullDefault)

not null -> o.toString()

null -> nullDefault

 

객체 문자 정보

package textbook.chapter11.exam01;

 

import java.util.Objects;

 

public class ToStringExample {

           public static void main(String[] args) {

                       String str1 = "홍길동";

                       String str2 = null;

                      

                       System.out.println(Objects.toString(str1));

                       System.out.println(Objects.toString(str2));

                       System.out.println(Objects.toString(str2,"이름이 없습니다."));

           }

}

 

11.5 System 클래스

v  System 클래스 용도

System.lang패키지에 있는 System 클래스를 이용하면 운영체제의 기능 일부 이용 가능

      프로그램 종료, 키보드로부터 입력, 모니터 출력, 메모리 정리, 현재 시간 읽기

      시스템 프로퍼티 읽기, 환경 변수 읽기

자바 프로그램은 운영체제상에서 바로 실행되는 것이 아니라 jvm위에서 실행된다. 따라서 운영체제의 모든 기능을 자바 코드로 직접 접근하기란 어렵다.

System.클래스의 모든 필드와 메소드는 정적(static) 필드와 정적(static)메소드로 구성되어 있다.

 

11.5.1프로그램 종료(exit())

기능  - 강제적으로 JVM 종료

      int 매개값을 지정하도록 - 종료 상태 값

정상 종료일 경우 0, 비정상 종료일 경우 0 이외 다른 값

어떤 값 주더라도 종료

      만약 특정 상태 값이 입력되었을 경우에만 종료하고 싶다면?

자바의 보안 관리자 설정

어떠한 값을 주더라도 종료가 되는데, 특정 값이 입력되었을 경우에만 종료를 하고 싶다면 

자바의 보안 관리자를 직접 설정해서 종료 상태값을 확인하면 됩니다

System.exit()가 실행되면 보안 관리자의 checkExit()메서드가 자동 호출되는데

이 메서드에서 종료 상태값을 조사해서 특정 값이 입력되지 않으면

SecurityException을 발생시켜 System.exit()를 호출한 곳에서 예외처리를 할 수 있도록 해줍니다.

checkExit()가 정상적으로 실행되면 JVM은 종료됩니다

아래는 종료 상태 값으로 5가 입력되면 JVM을 종료하도록 보안관리자를 설정한 것입니다.

System.setSecurityManager(new SecurityManaget() {

   @Override

    public void checkExit(int status) {

       in(status != 5){

           throws new SecurityException();

       }

    }

});

 

exit메소드 종료상태값이 5일 경우

public class ExitExample {

           public static void main(String[] args) {

                       //보안 관리자 설정

                       System.setSecurityManager(new SecurityManager() {

                                  @Override

                                  public void checkExit(int status) {

                                              if(status != 5) {

                                                         throw new SecurityException();

                                              }

                                  }

                       });

                      

                       for(int i = 0; i < 10; i++) {

                                  //i값 출력

                                  System.out.println(i);

                                  try {

                                              //JVM종료 요청

                                              System.exit(i);

                                  }catch(SecurityException e) {}

                       }

           }

}

 

11.5.2 쓰레기 수집기 실행(gc())

 

 

 

 

 

 

 

 

 

 

Car myCar = new Car();//이전 참조 객체

myCar = new Car();//현재 참조 객체

 

 

 

 

자바는 메모리를 JVM이 알아서 자동으로 관리합니다. 메모리가 부족할 때와 CPU가 한가할 때에 

가비지 컬렉터를 실행시켜 사용하지 않는 객체를 자동 제거

Cars myCar = new Cars(); 를 선언한 후 

myCar = null; 다시 null을 대입했다면 myCar는 객체의 번지를 잃게 됩니다

객체의 번지를 모르니 더 이상 Car 객체는 사용할 수가 없고 이제부터 쓰레기가 됩니다.

또는

Cars myCar = new Cars(); // 이전 참조 객체

myCar = new Cars(); // 현재 참조 객체 

이전 객체 번지를 잃었기 때문에 이전 객체는 쓰레기가 됩니다.

 

Garbage Collector는 직접 코드로 실행시킬 수는 없고

JVM에게 가능한한 빨리 실행해 달라고 요청은 할 수 있습니다. 이것이 System.gc() 메서드입니다

System.gc() 메서드가 호출되면 쓰레기 수집기가 바로 실행되는 것은 아니고 

JVM은 빠른 시간 내에 실행시키기 위해 노력합니다.

System.gc()

 

gc() 메서드는 메모리가 열악하지 않은환경이라면 거의 사용할 일이 없습니다

 

gc메소드

public class GcExample {

           public static void main(String[] args) {

                       Employee emp;

                      

                       emp = new Employee(1);//쓰레기가 됨

                       emp = null;

                       emp = new Employee(2);//쓰레기가 됨

                       emp = new Employee(3);

                      

                       System.out.print("emp가 최종적으로 참조하는 사원번호 : ");

                       System.out.println(emp.eno);

                       System.gc();//쓰레기 수집기 실행 요청

           }

}

 

class Employee{

           public int eno;

 

           public Employee(int eno) {

                       this.eno = eno;

                       System.out.println("Emplyee(" +eno+") 가 메모리에 생성됨");

           }

          

           public void finalize() {

                       System.out.println("Emplyee(" +eno+") 가 메모리에 제거됨");//소멸자

           }

}

 

11.5.3 현재 시각 읽기(currentTimeMillis(),nanoTime())

    • 현재 시간을 읽어 밀리 세컨드(currentTimeMillis() -> 1/1000) 와 나노세컨드(nanoTime()->1/109) 단위의 long값 리턴

 

    • 주로 프로그램 실행 소요 시간 구할 때 이용

 

주로 프로그램의 실행 소요 시간 측정에 사용됩니다

프로그램 시작 시 시각을 읽고 

프로그램이 끝날 때 시각을 읽어서 차이를 구하면 프로그램 실행 송 시간이 나옵니다.

 

프로그램 실행 요소 시간 구하기

public class TimeExample {

           public static void main(String[] args) {

 

                       long time1 = System.nanoTime();//시작 시간 읽기

                      

                       int sum = 0;

                       for (int i = 1; i <= 1000000; i++) {

                                  sum += i;

                       }

 

                       long time2 = System.nanoTime(); //끝 시간 읽기

 

                       System.out.println("1~1000000까지의 합: " + sum);

                       System.out.println("계산에 " + (time2 - time1) + " 나노초가 소요되었습니다.");

 

           }

}

 

11.5.4 시스템 프로퍼티 읽기(getProperty())

    • 시스템 프로퍼티란?

      JVM이 시작할 때 자동 설정되는 시스템의 속성값

    • 대표적인 키와 값

 

    • 시스템 프로퍼티 읽어오는 법

 

 

시스템 프로퍼티 읽기

public class GetProperyExample {

           public static void main(String[] args) {

                       // 개별 속성 읽기

                       String osName = System.getProperty("os.name");

                       String userName = System.getProperty("user.name");

                       String userHome = System.getProperty("user.home");

 

                       System.out.println("운영체제 이름: " + osName);

                       System.out.println("사용자 이름: " + userName);

                       System.out.println("사용자 홈디렉토리: " + userHome);

 

                       System.out.println("---------------------------------");

                       System.out.println(" [ key ]  value");

                       System.out.println("---------------------------------");

                      

                       // 모든 속성의 키와 값을 출력

                       Properties props = System.getProperties();

                       Set keys = props.keySet();

                       for(Object objKey: keys) {

                                  String key =(String)objKey;

                                  String value = System.getProperty(key);

                                  System.out.println("[ " + key + " ]  " + value);

                       }

           }

}

 

11.5.5 환경 변수 읽기(getenv())

    • 운영체제가 제공하는 환경 변수 값 (문자열) 을 읽음

 

 

JAVA_HOME 환경 변수 값 얻기

public class SystemEnvExample {

           public static void main(String[] args) {

                       String javaHome = System.getenv("JAVA_HOME");

                       System.out.println("JAVA_HONE: "+ javaHome);

           }

}

 

11.6 Class 클래스

    • 클래스와 인터페이스의 메타 데이터 관리 java.lang패키지

      메타데이터: 클래스의 이름, 생성자 정보, 필드 정보, 메소드 정보

 

11.6.1 Class 객체 얻기(getClass(), forName())

객체로부터 얻는 방법

문자열로부터 얻는 방법

 

Object는 모든 클래스의 최상위

 

getClass() 메서드는 해당 클래스로 객체를 생성했을 때만 사용할 수 있습니다

객체를 생성하기 전에 직접 Class 객체를 얻을 수도 있습니다

Class는 생서자를 감추고 있기 때문에 new 연산자로 객체를 만들 수 없고 

정적 메서드는 forName()을 이용해야 합니다

forName() 메서드는 클래스 전체 이름(패키지가 포함된 이름) 을 매개값으로 받고 

Class 객체를 리턴합니다.

try{

  Class clazz = Class.forName(String ClassName);

} catch(ClassNotFoundException e){

}

 

Class.forName() 메서드는 매개값으로 주어진 클래스를 찾지 못하면 

ClassNotFoundException 예외를 발생시키기 때문에 예외 처리가 필요.

 

public class Car {

           public String model;

          

           public Car() {

                       super();

           }

 

           public Car(String model) {

                       this.model = model;

           }

}

 

getClassforName()예제

public class ClassExample {

           public static void main(String[] args) {

                       Car car = new Car();

                       Class clazz1 = car.getClass();

                       System.out.println(clazz1.getName());

                       System.out.println(clazz1.getSimpleName());

                       System.out.println(clazz1.getPackage().getName());

                       System.out.println();

                      

                       try {

                                  Class clazz2 = Class.forName("textbook.chapter11.Car");

                                  System.out.println(clazz1.getName());

                                  System.out.println(clazz1.getSimpleName());

                                  System.out.println(clazz1.getPackage().getName());

                       } catch (ClassNotFoundException e) {

                                  e.printStackTrace();

                       }

           }

}

 

11.6.2 리플렉션 getDeclaredConstructors(), getDeclaredFields(), getDeclaredMethods()

    • 클래스의 생성자, 필드, 메소드 정보를 알아내는 것

 

리플렉션 : Class 객체를 이용하면 클래스의 생성자, 필드, 메서드 정보를 알아낼 수 있습니다.  Class 객체는 리플렉션을 위해

getDeclaredConstructors(), getDeclaredFields(), getDeclaredMethods() 를 제공합니다.

Constructor[] constructors = clazz.getDeclaredConstructors();

Field[] fields = clazz.getDeclaredFields();

Method[] methods = clazz.getDeclaredMethods();

 

위 메서드는 각각 생성자 배열, 필드 배열, 메서드 배열을 리턴합니다

Constructor, Field, Method 클래스는 java.lamg.reflect 패키지에 소속되어 있습니다.

getDeclaredFields(), getDeclaredMethods()는 클래스에 선언된 멤버만 가져옵니다.

상속된 멤버도 얻고 싶다면 getFields(), getMethods()  이용하면 됩니다

getFields(), getMethods() public 멤버만 가져옵니다

 

동적으로 클래스 멤버 정보 얻기

package textbook.chapter11;

 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

public class ReflectionExample {

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

                       Class clazz = Class.forName("textbook.chapter11.Car");

                      

                       System.out.println("[클래스 이름]");

                       System.out.println(clazz.getName());

                       System.out.println();

                      

                       System.out.println("[생성자 정보]");

                       //생성자 이름과 매개 변수 정보를 출력

                       Constructor[] constructors = clazz.getDeclaredConstructors();

                       for(Constructor constructor: constructors) {

                                  System.out.print(constructor.getName() +"(");

                                  Class[] parameters = constructor.getParameterTypes();

                                  printParameters(parameters);

                                  System.out.print(")");

                       }

                       System.out.println();

                      

                       System.out.println("[메소드 정보]");

                       //필드 타입과 필드 이름을 출력

                       Field[] fields = clazz.getDeclaredFields();

                       for (Field field : fields) {

                                  System.out.println(field.getType().getSimpleName()+" "+field.getName());

                       }

                       System.out.println();

                      

                       System.out.println("[생성자 정보]");

                       //메소드 이름과 매개 변수를 출력

                       Method[] methods = clazz.getDeclaredMethods();

                       for (Method method : methods) {

                                  System.out.print(method.getName() +"(");

                                  Class[] parameters = method.getParameterTypes();

                                  printParameters(parameters);

                                  System.out.print(")");

                       }

                       System.out.println();

                      

           }

          

           ///매개 변수 정보를 출력하는 공통 코드

           private static void printParameters(Class[] parameters) {

                       for (int i = 0; i < parameters.length; i++) {

                                  System.out.print(parameters[i].getName());

                                  if(i<(parameters.length-1)) {

                                              System.out.print(",");

                                  }

                       }

           }

}

 

11.6.3 동적 객체 생성(newInstance())

    • 실행 도중 클래스 이름이 결정될 경우 동적 객체 생성 가능

 

 

Class 객체를 이용하면 new 연산자의 사용 없이 동적으로 객체 생성이 가능합니다

코드 작성 시에 클래스 이름을 결정할 수 없고, 런타임 시에 클래스 이름이 결정되는 경우에

매우 유용합니다

아래 코드처럼 Class.forName() 메서드로 Class 객체를 얻음 다음 newInstance()메서드를 호출하면 Object 타입의 객체를 얻을 수 있습니다.

 

try{

   Class clazz = Class.forName("런타임 시 결정되는 클래스의 이름");

   Object obj = clazz.newInstance();

}catch(ClassNotFoundException e){

}catch(InstantiationException e){

}catch(IllegalAccessException e){

}

 

newInstance() 메서드는 기본 생성자를 호출해서 객체를 생성하기 때문에 반드시 클래스에 기본 생성자가 존재해야 합니다. 매개 변수가 있는 생성자를 호출하고 싶다면 리플랙션으로 Constructor 객체를 

얻어 newInstance() 메서드를 호출하면 됩니다.

newInstance() 메서드는 두 가지 예외가 발생할 수 있는데

InstantiationException예외는 해당 클래스가 추상 클래스이거나 인터페이스일 경우에 발생하고,

IllegalAccessException 예외는 클래스나 생성자가 접근 제한자로 인해 접근할 수 없을 경우에 

발생합니다. 그렇기에 예외 처리가 필요합니다.

 

newInstance() 메서드의 리턴 타입은 Object이므로 이것을 원래 클래스 타입으로 변환해야만 메서드를 사용할 수 있습니다. 그렇게 하기 위해 강제 타입 변환을 해야하는데 클래스타입을 모르는 상태이기에 변환을 할 수가 없습니다. 이 문제를 해결하기위해서는 인터페이스의 사용이 필요합니다.


Class clazz = Class.forName("SendAction"
또는 "ReceiveAction");

Action action= (Action)clazz.newInstance();

action.execute();//SendAction()또는 ReceiveActionexecute()가 실행됨

 

인터페이스

public interface Action {

           public void execute();

}

 

발신 클래스

public class SendAction implements Action{

 

           @Override

           public void execute() {

                       System.out.println("데이터를 보냅니다.");

           }

 

}

 

수신 클래스

public class ReceiveAction implements Action{

 

           @Override

           public void execute() {

                       System.out.println("데이터를 받습니다.");

           }

 

}

 

동적 객체 생성 및 실행

public class NewInstanceExample {

           public static void main(String[] args) {

                       try {

                                  Class clazz = Class.forName("textbook.chapter11.SendAction");

                                  //Class clazz = Class.forName("textbook.chapter11.ReceiveAction");

                                  Action action = (Action)clazz.newInstance();

                                  action.execute();

                       } catch (ClassNotFoundException e) {

                                  e.printStackTrace();

                       }catch (InstantiationException e) {

                                  // TODO Auto-generated catch block

                                  e.printStackTrace();

                       } catch (IllegalAccessException e) {

                                  // TODO Auto-generated catch block

                                  e.printStackTrace();

                       }

           }

}

11.7 String 클래스

11.7.1 String 생성자

byte[] 배열을 문자열로 변환하는 생성자

문자열은 String 클래스의 인스턴스로 관리됩니다

소스 상에서 문자열 리터럴은 String 객체로 자동 생성됩니다

또한 String 클래스의 다양한 생성자를 이용해서 직접 String 객체를 생성할 수도 있습니다.

 String 클래스는 Deprecated 된 생성자를 제외하면 13개 정도의 생성자를 제공합니다

Deprecated는 현재 버전 이후로는 사용하지 말라는 의미를 담고 있습니다

어떤 생성자를 이용해서 String 객체를 생성할지는 제공되는 매개값의 타입에 달려있습니다

아래 생성자들은 사용되는 빈도 수가 높은 생성자들입니다

파일의 내용을 읽거나 네트워크를 통해 받은 데이터는 보통 byte[] 배열이므로 이것을 문자열로 변환하기 위해 사용됩니다.

 

 

바이트 배열을 문자열로 변환

public class ByteToStringExample {

           public static void main(String[] args) {

                       byte[] bytes = { 72, 101, 108, 108, 111, 32, 74, 97, 118, 97  };

                      

                       String str1= new String(bytes);

                       System.out.println(str1);

                      

                       //6 74번 위치 4 4

                       String str2 = new String(bytes, 6, 4);

                       System.out.println(str2);

           }

}

 

System.in.read() 메서드는 키보드에서 입력한 내용을 매개값으로 주어진 바이트 배열에 저장하고 읽은 바이트 수를 리턴합니다

 영어는 1바이트이고 한글이나 기타 다른 나라언어는 2바이트로 표현됩니다

때문에 입력된 문자 수와 읽은 바이트 수는 다를 수 있습니다

 

키보드로부터 읽은 바이트 배열을 문자열로 변환

 

 

 

 

 

 

 

 

 

 

 

 

바이트 배열을 문자열로 변환

 

 

 

11.7.2 String 메소드

문자열의 추출, 비교, 찾기, 분리, 변환등과 같은 다양한 메소드 가짐

사용 빈도 높은 메소드

 

 

    • 문자 추출(charAt())

      매개 값으로 주어진 인덱스의 문자 리턴

 

매개값으로 주어진 인덱스의 문자를 리턴하는 매서드

 인덱스란 배열의 인덱스와 마찬가지로 길이-1까지의 번호입니다.

 

 

 

주민등록번호에서 남자와 여자를 구분하는 방법

public class StringCharAtExample {

           public static void main(String[] args) {

                       String ssn ="010624-1230123";

                       char sex = ssn.charAt(7);

                       switch (sex) {

                       case '1':

                       case '3':

                                  System.out.println("남자입니다.");

                                  break;

                       case '2':

                       case '4':

                                  System.out.println("여자입니다.");

                                  break;

                       }

           }

}

 

    • 문자열 비교(equals())

      문자열 비교할 때 == 연산자 사용하면 원하지 않는 결과 발생!

 

 

문자열을 == 연산자로 비교하게 되면 각 변수에 저장된 번지를 비교하기 때문에 

원하지 않는 결과를 얻는 경우가 생깁니다.

그냥 두 문자의 문자열 만을 비교하고 싶다면 equals() 메서드를 사용해야 합니다.

원래 equals() 메서드는 Object 클래스의 번지 비교 메서드이지만 

String 클래스가 오버라이딩해서 문자열을 비교하도록 변경하였습니다.

 

문자열 비교

public class StringEqualExample {

           public static void main(String[] args) {

                       String strVar1 = new String("신민철");

                       String strVar2 = "신민철";

 

                       if (strVar1 == strVar2) {

                                  System.out.println("같은 String 객체를 참조");

                       } else {

                                  System.out.println("다른 String 객체를 참조");

                      }

 

                       if (strVar1.equals(strVar2)) {

                                  System.out.println("같은 문자열을 가짐");

                       } else {

                                  System.out.println("다른 문자열을 가짐");

                       }

           }

}


 

    • 바이트 배열로 변환(getBytes())

      시스템의 기본 문자셋으로 인코딩된 바이트 배열 얻기

 

      특정 문자셋으로 인코딩 된 바이트 배열 얻기

[참고] 디코딩

 

 

 

 네트워크로 문자열을 전송하거나 문자열을 암호화할 경우 문자열을 바이트 배열로 변환합니다.

문자열을 바이트 배열로 변환하는 메서드는 아래 두 가지가 있습니다

byte[] bytes = "문자열".getBytes();

byte[] bytes = "문자열".getBytes(Charset charset);

getBytes() 메서드는 시스템의 기본 문자셋으로 인코딩된 바이트 배열을 리턴합니다

특정 문자셋으로 인코딩된 바이트배열을 얻으려면 두 번째 메서드를 사용하면 됩니다.

getBytes(Charset charset);메서드는 잘못된 문자셋을 매개값으로 줄 경우 java.io.UnsupportedEncodingException예외가 발생하므로 예외처리가 필요.

try{

   byte[] bytes = "문자열".getBytes("EUC-KR");

   byte[] bytes = "문자열".getBytes("UTF-8");

}catch(UnsupportedEncodingException e) {

}

어느 문자셋으로 인코딩 하느냐에 따라 바이트 배열의 크기가 달라집니다

EUC-KR getBytes()와 마찬가지로 알파벳은 1바이트, 한글은 2바이트로 변환한고 

UTF-8은 알파벳은 1바이트 한글은 3바이트로 변환합니다.


바이트 배열로 변환

public class StringGetBytesExample {

           public static void main(String[] args) {

                       String str = "안녕하세요";

 

                       // 기본 문자셋으로 인코딩과 디코딩

                       byte[] bytes1 = str.getBytes();

                       System.out.println("bytes1.length: " + bytes1.length);

                       String str1 = new String(bytes1);

                       System.out.println("bytes1->String: " + str1);

 

                       try {

                                  //euc-kr 을 이용해서 인코딩 및 디코딩

                                  byte[] bytes2 = str.getBytes("EUC-KR");

                                  System.out.println("bytes2.length: " + bytes2.length);

                                  String str2 = new String(bytes2, "EUC-KR");

                                  System.out.println("bytes2->String: " + str2);

                                 

                                  //UTF-8 을 이용해서 인코딩 및 디코딩

                                  byte[] bytes3 = str.getBytes("UTF-8");

                                  System.out.println("bytes3.length: " + bytes3.length);

                                  String str3 = new String(bytes3, "UTF-8");

                                  System.out.println("bytes3->String: " + str3);

                       } catch (UnsupportedEncodingException e) {

                                  e.printStackTrace();

                       }

 

           }

}

 

    • 문자열 찾기(indexOf())

매개값으로 주어진 문자열이 시작되는 인덱스 리턴

주어진 문자열이 포함되어 있지 않으면 -1 리턴

 

 

 

 

특정 문자열이 포함되어 있는지 여부 따라 실행 코드 달리할 때 사용

if문의 조건식에서 특정 문자열이 포함되어 있는지 여부에 따라 실행 코드를 달리할 때 자주 사용됩니다.
if(
문자열.indexOf("찾는문자열") != -1){

           //포함되어 있는 경우

}else{

           //포함되어 잇지 않는 경우

}

문자열 포함 요부 조사

public class StringIndexOfExample {

           public static void main(String[] args) {

                       String subject = "자바 프로그래밍";

 

                       int location = subject.indexOf("프로그래밍");

                       System.out.println(location);// 자바 프로그래밍에서 "프로그래밍" 문자열의 인덱스 위치 가 3이기 때문에 3을 출력합니다.

 

                       if (subject.indexOf("자바") != -1) {

                                  System.out.println("자바와 관련된 책이군요");

                       } else {

                                  System.out.println("자바와 관련없는 책이군요");

                       }

           }

}

 

    • 문자열 길이(length()) – 공백도 문자에 포함

 

 

 

 

 

 

문자열이 문자 수 얻기

public class StringLengthExample {

           public static void main(String[] args) {

                       String ssn = "7306241230123";

                       int length = ssn.length();

                       if (length == 13) {

                                  System.out.println("주민번호 자리수가 맞습니다.");

                       } else {

                                  System.out.println("주민번호 자리수가 틀립니다.");

                       }

           }

}

 

    • 문자열 대치(replace())

      첫 번째 매개값인 문자열 찾음

      두 번째 매개값인 문자열로 대치

      새로운 문자열 리턴

 

 

 

 

 

 

 

 

 

 

 

 

 

 

replace() 메소드가 리턴하는 문자열은 원래 문자열의 수정본이 아니라 완전한 새로운 문자열이다.

 

문자열 대치하기

public class StringReplaceExample {

           public static void main(String[] args) {

                       String oldStr = "자바는 객체지향 언어닙니다.자바는 풍부한 api를 지원합니다.";

                       String newStr = oldStr.replace("자바", "JAVA");

 

                       System.out.println(oldStr);

                       System.out.println(newStr);

           }

}

 

    • 문자열 잘라내기(substring())

      substring(int beginIndex, int endIndex)

 주어진 시작과 끝 인덱스 사이의 문자열 추출

      substring(int beginIndex)

 주어진 인덱스 이후부터 끝까지 문자열 추출

 

 

 

 

 

 

 

 

문자열 추출하기

public class StringSubstringExample {

           public static void main(String[] args) {

                       String ssn = "880815-1234567";

                       String firstNum = ssn.substring(0, 6);

                       System.out.println(firstNum);

                       String secondNum = ssn.substring(7);

                       System.out.println(secondNum);

           }

}

 

알파벳 소∙대문자 변경 (toLowerCase(), toUpperCase())

 

 

 

전부 소문자 또는 대문자로 변경

public class StringToLowerUpperExample {

           public static void main(String[] args) {

                       String str1= "Java Programming";

                       String str2= "JAVA Programming";

                      

                       System.out.println(str1.equals(str2));

                      

                       String lowerStr1 = str1.toLowerCase();

                       String lowerStr2 = str2.toLowerCase();

                       System.out.println(lowerStr1.equals(lowerStr2));

                      

                       System.out.println(str1.equalsIgnoreCase(str2));

           }

}

 

v  문자열 앞뒤 공백 잘라내기(trim())

 

 

 

문자열의 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴하는 메서드.  

이 메서드는 앞뒤 공백만 제거하고 문자열 사이의 공백은 제거하지 않습니다.

 

앞뒤 공백 제거

public class StringTrimExample {

           public static void main(String[] args) {

                       String tel1 = "  02";

                       String tel2 = "123   ";

                       String tel3 = "   1234   ";

 

                       String tel = tel1.trim() + tel2.trim() + tel3.trim();

                       System.out.println(tel);

           }

}

 

    • 문자열 변환(valueOf())

      기본 타입의 값을 문자열로 변환

 

 

기본 타입 값을 문자열로 변환

public class StringValueOfExample {

           public static void main(String[] args) {

                       String str1 = String.valueOf(10);

                       String str2 = String.valueOf(10.5);

                       String str3 = String.valueOf(true);

 

                       System.out.println(str1);

                       System.out.println(str2);

                       System.out.println(str3);

           }

}

 

11.8 StringTokenizer 클래스

문자열이 특정 구분자로 연결되어 있을 경우 구분자를 기준으로 부분 문자열을 분리하기 위해서는 String split () 메서드를 사용하거나 StringTokenizer 클래스를 사용할 수 있습니다.

split()은 정규 표현식으로 구분하고, StringTokenizer는 문자로 구분한다는 차이점이 있습니다.

v  문자열 분리 방법

§  String split() 메소드 이용

§  java.util.StringTokenizer 클래스 이용

11.8.1 String split()

§  정규표현식을 구분자로 해서 부분 문자열 분리

§  배열에 저장하고 리턴



 

정규 표현식을 구분자로 해서 문자열을 분리한 후 배열에 저장하고 리턴.

String[] strs = "문자열".split("정규표현식");

문자열 분리

public class StringSplitExample {

           public static void main(String[] args) {

                       String text = "홍길동&이수홍,박연수,김자바-최명호";           

String[] names = text.split("&|,|-"); // 제외하고 싶은 문자열을 |로 구분하여 작성합니다.

                       for (String name : names) {

                                  System.out.println(name);

                       }

           }

}

11.8.2 StringTokenizer 클래스

문자열이 한 종류의 구분자로 연결되어 있는 경우, 손쉽게 문자열을 분리할 수 있습니다.

StringTokenizer st = new StringTokenizer("문자열","구분자"); 구분자를 생략하면 공백이 기본 구분자가 됩니다

문자열이 "/"로 구분되어있을 경우 아래처럼 할 수 있습니다.
만약
구분자가 생략하면 공백이 기본 구분자가 된다.

 

 

nextToken() 메서드로 토큰을 하나 꺼내오면 StringTokenizer 객체에는 해당 토큰이 없어집니다

StringTokenizer 객체에서 더 이상 가져올 토큰이 없다면 nextToken() 메서드는 java.util.NoSuchElementException 예외를 발생시킵니다. 그렇기 때문에 nextToken() 메서드를 사용하기 전에 hasMoreTokens() 메서드로 꺼내올 토큰이 있는지 여부를 조사한 후 nextToken() 메서드를 호출하는 것이 좋은 코딩 방법입니다.


StringTokenizer
로 토큰 분리하기

public class StringTokenizerExample {

           public static void main(String[] args) {

                       String text = "티스토리/블로그/알통몬";

                      

                       //how1: 전체 토큰 수를 얻어 for문으로 루핑

                       StringTokenizer st = new StringTokenizer(text,"/");

                       int countTokens = st.countTokens();

                       for(int i = 0; i <countTokens ; i++) {

                                  String token = st.nextToken();

                                  System.out.println(token);

                       }

                      

                       System.out.println();

                      

                       //how2:남아 있는 토큰을 확인하고 while문으로 루핑

                       st  = new StringTokenizer(text,"/");

                       while(st.hasMoreTokens()) {

                                  String token = st.nextToken();

                                  System.out.println(token);

                       }

           }

}

 

11.9.StringBuffer, StringBuilder 클래스

v  문자열 결합 연산자 +

String 은 내부의 문자열 수정 불가 -> 대치된 새로운 문자열 리턴

 

문자열을 변경하는 작업이 많을 경우 String 클래스를 사용하는 것보다는

java.lang 패키지의 StringBuffer 또는 StringBuilder 클래스를 사용하는 것이 좋습니다

이 두 가지 클래스는 내부 버퍼에 문자열을 저장해 두고, 그 안에서 추가, 수정, 삭제 작업을 할 수 있도록 설계되어 있습니다

문자열을 결합하는 + 연산자를 많이 사용할 수 록 그만큼 String 객체의 수가 늘어나기 때문에 .프로그램 성능을 느리게 하는 요인이 된다.

v  StringBuffer, StringBuilder (p.514~516)

버퍼(buffer:데이터를 임시로 저장하는 메모리)에 문자열 저장

버퍼 내부에서 추가, 수정, 삭제 작업 가능

멀티 스레드환경: StringBuffer 사용 동기화가 적용되어 있어 스래드에 안전하지만

단일 스레드환경: StringBuilder 사용

 

StringBuilder 클래스 ->버퍼 크기를 늘린다.

 몇 가지 생성자를 제공합니다.  기본 생서자인StringBuilder() 16개 문자들을 저장할 수 있는 초기 버퍼를 만들고, StringBuilder(int capacity) 생성자는 capacity 로 주어진 개수만큼 문자들을 저장할 수 있는 초기 버퍼를 만듭니다. 그리고 StringBuilder는 버퍼가 부족할 경우 자동적으로 버퍼의 크기를 늘리기 떄문에 초기 버퍼의 크기는 크게 중요하지 않습니다. StringBuilder(String str) 생성자는 str로 주어진 매개값을 버퍼의 초기값으로 저장합니다.

 

 

append() insert() 메서드는 매개 변수가 다양한 타입으로 오버로딩되어 있기 때문에 대부분의 값을 문자로 추가 또는 삽입할 수 있습니다.

StringBuilder
에서 문자열 조작

public class StringBuilderExample {

      public static void main(String[] args) {

                  //StringBuilder 객체 생성

                  StringBuilder sb = new StringBuilder();

                 

                  //문자열을 끝에 추가

                  sb.append("Java ");

                  sb.append("Program Stude");

                  System.out.println(sb.toString());

                 

                  //index4위체에 2를 삽입

                  sb.insert(4,"2");

                  System.out.println(sb.toString());

                 

                  //index4위치의 문자를 6으로 변경

                  sb.setCharAt(4, '6');

                  System.out.println(sb.toString());

                 

                  //index6부터 index13 ''까지를 'Book'문자열로 대치

                  sb.replace(6, 13, "Book");

                  System.out.println(sb.toString());

                 

                  //index4ㅇ부터 index ''까지 삭제

                  sb.delete(4, 5);

                  System.out.println(sb.toString());

                 

                  // 총 문자수 얻기

                  int length= sb.length();

                  System.out.println("총문자수: "+length);

                 

                  //버퍼에 있는 것을 String 타입으로 리턴

                  String result = sb.toString();

                  System.out.println(result);

                 

      }

}

 

11.10 정규 표현식과 Pattern 클래스

문자열이 정해져 있는 형식(정규 표현식)으로 구성되어 있는지 검증해야 하는 경우가 있습니다

이메일이나 전화변호를 사용자가 제대로 입력했는지 검증해야 할 때 정규 표현식과 비교합니다


문자열이 정해져 있는 형식으로 구성되어 있는지 검증할 때 사용

Ex) 이메일, 전화번호, 비밀번호 등

 

11.10.1 정규 표현식(Regular Expression) 작성 방법

    • 문자 또는 숫자 기호와 반복 기호가 결합된 문자열

java.util.regex.Pattern클래스를 찾아 Summary of regualr-expression construct를 참조하면 되는데 이해하기가 어렵지 않다.

 

 

(02|010)-\d{3,4}-\d{4}는 전화번호를 위한 정규 표현식입니다.

그리고

\w+@\w+\.\w+(\.\w+)? 이건

 rain483@naver.com 과 같은 이메일을 위한 정규 표현식입니다

주의할 점은 \. . 은 다릅니다. \.은 점(.)을 말하고 .은 모든 문자 중에서 한 문자를 뜻합니다.

 

11.10.2 Pattern 클래스

    • 정규 표현식으로 문자열을 검증하는 역할
      • 결과는 boolean 타입 !!!

 

문자열을 정규 표현식으로 검증하는 기능은 java.util.regex.Pattern 클래스의 정적 메서드인 matches() 메서드가 제공합니다.

문자열 검증하기

public class PatternExample {

      public static void main(String[] args) {

                  String regExp = "(02|010)-\\d{3,4}-\\d{4}";

                  String data = "010-123-4567";

                  boolean result = Pattern.matches(regExp, data);

                  if (result) {

                             System.out.println("정규식과 일치합니다.");

                  } else {

                             System.out.println("정규식과 일치하지 않습니다.");

                  }

                 

                  regExp = "\\w+@\\w+\\.\\w+(\\.\\w+)?";

                  data = "rain483@navercom";

                  result = Pattern.matches(regExp, data);

                  if (result) {

                             System.out.println("정규식과 일치합니다.");

                  } else {

                             System.out.println("정규식과 일치하지 않습니다.");

                  }

      }

}

 

11.11 Arrays 클래스

배열 조작 기능을 가지고 있는 클래스 - 배열 복사, 항목 정렬, 항목 검색

제공하는 정적 메소드

 

 

배열 조작 기능을 가지고 있습니다

배열 조작이란 : 배열의 복사, 항목 정렬, 항목 검색과 같은 기능

단순한 배열의 복사는 System.arrayCopy() 메서드를 사용할 수 있지만,

Arrays는 추가적으로 항목 정렬, 항목 검색, 항목 비교와 같은 기능을 제공해 줍니다.

 

전부 static 메서드이므로 Arrays 클래스로 바로 사용이 가능합니다.

 


11.1.1 배열 복사

 

      Arrays.copyOf(원본배열, 복사할 길이)

 0 ~ (복사할 길이-1)까지 항목 복사

 복사할 길이는 원본 배열의 길이보다 커도 되며 타겟 배열의 길이

 

      copyOfRange(원본 배열, 시작 인덱스, 끝 인덱스)

 시작인덱스 ~ (끝 인덱스-1)까지 항목 복사

 

 

      System.arraycopy()

 

 

단순히 배열을 복사할 목적으로 사용하는 System.arraycopy()메서드와 위 메서드들의 사용 에제를 보겠습니다.System.arraycopy()메서드는 5개의 매개 값이 필요합니다.

System.arraycopy(Object o,    int start,    Object o2,    int end, int length)

                     원본 배열 시작인덱스 타겟배열 타겟 시작인덱스 복사개수


배열 복사

public class ArrayCopyExample {

           public static void main(String[] args) {

                       char[] arr1 = { 'J', 'A', 'V', 'A' };

 

                       // 방법 1

                       // arr1 전체를 arr2로 복사

                       char[] arr2 = Arrays.copyOf(arr1, arr1.length);

                       System.out.println(Arrays.toString(arr2));

 

                       // 방법 2

                       // arr1[1] ~arr1[2] arr3[0]~arr3[]로 복사

                       char[] arr3 = Arrays.copyOfRange(arr1, 1, 3);

                       System.out.println(Arrays.toString(arr3));

 

                       // 방법 3

                       // arr1 전체를 ar4로 복사

                       char[] arr4 = new char[arr1.length];

                       System.arraycopy(arr1, 0, arr4, 0, arr1.length);

                       for (int i = 0; i < arr4.length; i++) {

                                  System.out.println("arr4[" + i + "]=" + arr4[i]);

                       }

           }

}

 

 

11.11.2 배열 항목 비교

      Arrays.equals(배열, 배열) - 1차 항목의 값만 비교

      Arrays.deepEquals(배열, 배열) -  중첩된 배열의 항목까지 비교

 

배열 비교

public class EqualsExample {

           public static void main(String[] args) {

                       int[][] original = { {1,2}, {3,4} };

                      

                       //얖은 복사후 비교

                       System.out.println("[얕은 복제후 비교]");

                       int[][] cloned1 = Arrays.copyOf(original, original.length);

                       System.out.println("배열 번지 비교: " + original.equals(cloned1));

                       System.out.println("1차 배열 항목값 비교:" +Arrays.equals(original, cloned1));

                       System.out.println("중업 배열 항목값 비교:" +Arrays.deepEquals(original, cloned1));

                      

                       //깊은 복사후 비교

                       System.out.println("[깊은 복제후 비교]");

                       int[][] cloned2 = Arrays.copyOf(original, original.length);

                       cloned2[0] = Arrays.copyOf(original[0], original[0].length);

                       cloned2[1] = Arrays.copyOf(original[1], original[1].length);

                       System.out.println("배열 번지 비교: " + original.equals(cloned2));

                       System.out.println("1차 배열 항목값 비교:" +Arrays.equals(original, cloned2));

                       System.out.println("중업 배열 항목값 비교:" +Arrays.deepEquals(original, cloned2));

           }

}

 

11.11.3 배열 항목 정렬

      Arrays.sort(배열)- 항목 오름차 순으로 정렬

기본 타입이거나 String 배열 자동 정렬

      사용자 정의 클래스 배열은 Comparable 인터페이스를 구현해야만 정렬

 

Comparable 구현 클래스

package textbook.chapter11.exam03;

 

public class Member implements  Comparable<Member> {

           String name;

           Member(String name){

                       this.name = name;

           }

          

           @Override

           public int compareTo(Member o) {

                       return name.compareTo(o.name);

           }

}

 

리턴 값은 오름 차순일 때 자신이 매개 값보다 낮을 경우 음수, 같을 경우 0, 높을 경우 양수를 리턴하도록 하고, 내림 차순일 경우 반대로 하면 됩니다

배열 비교

package textbook.chapter11.exam03;

 

import java.util.Arrays;

 

public class SortExample {

           public static void main(String[] args) {

                       int[] scores = { 99, 97, 98 };

                       Arrays.sort(scores);

                       for (int i = 0; i < scores.length; i++) {

                                  System.out.println("scores[" + i + "]=" + scores[i]);

                       }

 

                       System.out.println();

 

                       String[] names = { "홍길동", "박동수", "김민수" };

                       Arrays.sort(names);

                       for (int i = 0; i < names.length; i++) {

                                  System.out.println("names[" + i + "]=" + names[i]);

                       }

 

                       System.out.println();

 

                       Member m1 = new Member("홍길동");

                       Member m2 = new Member("박동수");

                       Member m3 = new Member("김민수");

                       Member[] members = { m1, m2, m3 };

                       Arrays.sort(members);

                       for (int i = 0; i < members.length; i++) {

                                  System.out.println("members[" + i + "].name=" + members[i].name);

                       }

           }

}

 

11.11.4 배열 항목 검색

      특정 값 위치한 인덱스 얻는 것

      Arrays.sort(배열)로 먼저 정렬

      Arrays.binarySearch(배열, 찾는 값) 메소드로 항목을 찾아야

 

배열 검색

public class SearchExample {

           public static void main(String[] args) {

                       // 기본 타입값 검색

                       int[] scores = { 99, 97, 98 };

                       Arrays.sort(scores);

                       int index = Arrays.binarySearch(scores, 99);

                       System.out.println("찾은 인덱스: " + index);

 

                       // 문자열 검색

                       String[] names = { "홍길동", "박동수", "박동수" };

                       Arrays.sort(names);

                       index = Arrays.binarySearch(names, "홍길동");

                       System.out.println("찾은 인덱스: " + index);

 

                       // 객체 검색

 

                       Member m1 = new Member("홍길동");

                       Member m2 = new Member("박동수");

                       Member m3 = new Member("박동수");

                       Member[] members = { m1, m2, m3 };

                       Arrays.sort(members);

                       index = Arrays.binarySearch(members, m1);

                       System.out.println("찾은 인덱스: " + index);

           }

}

 

 

11.12 포장(Wrapper) 클래스

v  포장(Wrapper) 객체란?

기본 타입(byte, char, short, int, long, float, double, boolean) 값을 내부에 두고 포장하는 객체

기본 타입의 값은 외부에서 변경 불가

 

 

11.12.1 박싱(Boxing)과 언박싱(Unboxing)

    • 박싱(Boxing): 기본 타입의 값을 포장 객체로 만드는 과정
    • 언박싱(Unboxing): 포장 객체에서 기본 타입의 값을 얻어내는 과정
    • 박싱 하는 방법

      생성자 이용

 

 

      valueOf() 메소드 이용

 

 

    • 언박싱 코드

      각 포장 클래스마다 가지고 있는 클래스 호출

      기본 타입명 + Value()

 

 

기본 타입의 값을 박싱하고 언박싱하기

public class BoxingUnBoxingExample {

           public static void main(String[] args) {

                       // Boxing

                       Integer obj1 = new Integer(100);

                       Integer obj2 = new Integer("200");

                       Integer obj3 = Integer.valueOf("300");

 

                       // Unboxing

                       int value1 = obj1.intValue();

                       int value2 = obj2.intValue();

                       int value3 = obj3.intValue();

 

                       System.out.println(value1);

                       System.out.println(value2);

                       System.out.println(value3);

           }

}

 

11.2.2 자동 박싱과 언박싱

자동 박싱 - 포장 클래스 타입에 기본값이 대입될 경우 발생

 

 

자동 언박싱 - 기본 타입에 포장 객체가 대입될 경우 발생

 

자동 방식과 언박싱

public class AntoBoxingUnBoxingExample {

           public static void main(String[] args) {

                       //자동 Boxing

                       Integer obj = 100;

                       System.out.println("value: " + obj.intValue());

                      

                       //대입 시 자동 Unboxing

                       int value = obj;

                       System.out.println("value: " +value );

                      

                       //연산 시 자동 Unboxing

                       int result = obj+ 100;

                       System.out.println("result: " + result);

           }

}

 

11.12.3 문자열을 기본 타입 값으로 변환

    • parse + 기본타입 명 à 정적 메소드

 

 

문자열을 기본 타입 값으로 변환

public class StringToPrimitiveValueExample {

           public static void main(String[] args) {

                       int value1 = Integer.parseInt("10");

                       double value2 = Double.parseDouble("3.14");

                       boolean value3 = Boolean.parseBoolean("true");

                      

                       System.out.println("value1: " +value1);

                       System.out.println("value2: " +value2);

                       System.out.println("value3: " +value3);

           }

}

 

11.12.4 포장값 비교

    • 포장 객체는 내부 값을 비교하기 위해   == != 연산자 사용 불가
    • 값을 언박싱해 비교하거나, equals() 메소드로 내부 값 비교할 것

Integer obj1 = 300;

Integer obj2 = 300;

System.out.println(obj1 == obj2); // true가 나와야 할 것 같지만 false가 나옵니다.

내부의 값만 비교하고 싶다면, 언박싱한 값을 비교해야 합니다

박싱된 값이 아래 표에 나와 있는 값이라면 == != 연산자로 내부의 값을 바로 비교할 수 있습니다

타입               값의 범위

boolean           true, false

char               \u0000~ \u007f

byte,short,int     -128~127


Wrapper
객체가 정확히 어떤 값이 저장될지 모른다면, ==, != 연산자는 사용하지 않는 것이 좋습니다.

내부 값을 언박싱해서 비교하거나 equals() 메서드로 내부 값을 비교하는 것이 좋습니다.

Wrapper 클래스의 equals() 메서드는 내부의 값을 비교하도록 오버라이딩되어 있습니다.

 

포장 객체 비교

public class ValueCompareExample {

           public static void main(String[] args) {

                       System.out.println("[-128~127 초과값일 경우]");

 

                       Integer obj1 = 300;

                       Integer obj2 = 300;

 

                       System.out.println("==결과: " + (obj1 == obj2));

                       System.out.println("언박싱후 ==결과: " + (obj1.intValue() == obj2.intValue()));

                       System.out.println("equals() 결과: " + obj1.equals(obj2));

                      

                       System.out.println();

 

                       System.out.println("[-128~127 범위값일 경우]");

 

                       Integer obj3 = 10;

                       Integer obj4 = 10;

 

                       System.out.println("==결과: " + (obj3 == obj4));

                       System.out.println("언박싱후 ==결과: " + (obj3.intValue() == obj4.intValue()));

                       System.out.println("equals() 결과: " + obj3.equals(obj4));

           }

}



11.13 Math, Random 클래스

11.3.1 Math 클래스 (예제는 p.533~536 참고)

수학 계산에 사용할 수 있는 정적 메소드 제공

 

 

Math의 수학 메소드

public class MathExample {

           public static void main(String[] args) {

                       int v1= Math.abs(-5);

                       double v2 = Math.abs(-3.14);

                       System.out.println("v1="+v1);

                       System.out.println("v2="+v2);

                      

                       double v3 = Math.ceil(5.3);

                       double v4 = Math.ceil(-5.3);

                       System.out.println("v3="+v3);

                       System.out.println("v4="+v4);

                      

                       double v5 = Math.floor(5.3);

                       double v6 = Math.floor(-5.3);

                       System.out.println("v5="+v5);

                       System.out.println("v6="+v6);

                      

                       int v7= Math.max(5,9);

                       double v8 = Math.max(5.3,2.5);

                       System.out.println("v7="+v7);

                       System.out.println("v8="+v8);

                      

                       int v9= Math.min(5,9);

                       double v10 = Math.min(5.3,2.5);

                       System.out.println("v9="+v9);

                       System.out.println("v10="+v10);

                      

                       double v11 = Math.random();

                       System.out.println("v11="+v11);

                      

                       double v12 = Math.rint(5.3);

                       double v13 = Math.rint(5.7);

                       System.out.println("v12="+v12);

                       System.out.println("v13="+v13);

                      

                       double v14 = Math.round(5.3);

                       double v15 = Math.round(5.7);

                       System.out.println("v14="+v14);

                       System.out.println("v15="+v15);

                      

                       //반올림하는 코드이다.

                       double value = 12.3456;

                       double temp1= value * 100;

                       long temp2 = Math.round(temp1);

                       double v16 = temp2/100.0;

                       System.out.println("v16="+v16);

                      

           }

}

 

Math.random() 메서드로 난수 얻기, 난수 발생 시키기

 

Math.random() 메서드는 0.0 1.0 사이의 double 타입 값을 리턴합니다. 0.0은 포함하지만 1.0은 포함하지 않습니다.  0.0<= math.random() <1.0

 

Math.random() 을 이용해서 0~10 사이의 정수 랜덤하게 얻고 싶다면 아래처럼 하면 됩니다.

   1 <= ((int)Math.random() * 10) +1 < 11

이것을 사용해서 로또 번호를 뽑거나 주사위를 굴리는 예제를 만들 수 있습니다.

 

예제1 : 주사위 번호 뽑기

int num = (int)(Math.random() * 6) +1;

 

예제2: 로또 번호 뽑기

int num = (int)(Math.random() * 45) +1;

 

임의의 주사위의 눈 얻기

public class MathRandomExample {

           public static void main(String[] args) {

                       int num = (int) (Math.random() * 6) + 1; // 1~6사이 숫자

                       System.out.println("주사위 눈: " + num);

           }

}

 

11.3.2 Random 클래스

    • boolean, int, long, float, double 난수 입수 가능
    • 난수를 만드는 알고리즘에 사용되는 종자값(seed) 설정 가능

      종자값이 같으면 같은 난수

    • Random 클래스로 부터 Random객체 생성하는 방법
    • Random 클래스가 제공하는 메소드

로또 번호 얻기

public class RandomExample {

           public static void main(String[] args) {

                       // 선택번호

                       int[] selectNumber = new int[6];

                       Random random = new Random(3);

                       // 당첨 번호 같은 종자값을 주면 계속 당첨이 됩니다.

                       // 그리고 종자값을 지정하지 않으면 매번 다른 번호가 나오고 종자값을

                       // 지정해주면 계속 실행하더라도 계속 같은 번호가 나옵니다. 아래 당첨번호도 마찬가지

                       System.out.print("선택 번호: ");

                       for (int i = 0; i < 6; i++) {

                                  selectNumber[i] = random.nextInt(45) + 1;

                                  System.out.print(selectNumber[i] + " ");

                       }

                       System.out.println();

 

                       // 당첨번호

                       int[] winningNumber = new int[6];

                       random = new Random(5);

                       System.out.print("당첨 번호: ");

                       for (int i = 0; i < 6; i++) {

                                  winningNumber[i] = random.nextInt(45) + 1;

                                  System.out.print(winningNumber[i] + " ");

                       }

                       System.out.println();

 

                       // 당첨여부

                       Arrays.sort(selectNumber);

                       Arrays.sort(winningNumber);

                       boolean result = Arrays.equals(selectNumber, winningNumber);

                       System.out.print("당첨 여부: ");

                       if (result) {

                                  System.out.println("1등에 당첨되셨습니다.");

                       } else {

                                  System.out.println("당첨되지 않았습니다.");

                       }

           }

}

 

1) 종자값을 동일하게 해준 경우

 계속 같은 값이 나옵니다.

2) 종자값을 다르게 해준 경우 

 서로 종자값이 다르기 때문에 당첨이 불가능합니다.

3) 종자값을 주지 않은 경우

두 번호 모두 계속 다른 번호가 나옵니다.

 

그리고 난수는 따로 if문을 설정해주지 않으면 같은 번호가 나올 수 있습니다.


11.4 Date, Calendar 클래스

java.util에 있다.

11.4.1 Date 클래스

    • 날짜를 표현하는 클래스
    • 날짜 정보를 객체간에 주고 받을 때 주로 사용

 

대부분이 Deprecated되어있고 Date() 생성자만 주로 사용합니다

toString()
메서드를 사용하면 현재 날짜를 문자열로 얻을 수 있습니다

toString() 메서드는 영문으로 된 날짜를 리턴합니다


현재 날짜를 출력하기

import java.text.SimpleDateFormat;

import java.util.Date;

 

public class DateExample {

           public static void main(String[] args) {

                       Date now = new Date();

                       String strNow1 = now.toString();

                       System.out.println(strNow1);

 

                       SimpleDateFormat sdf = new SimpleDateFormat("yyyy MM dd hh mm ss");

                       String strNow2 = sdf.format(now);

                       System.out.println(strNow2);

           }

}

 

11.14.2 Calendar 클래스

    • 달력을 표현한 추상 클래스
    • OS에 설정된 시간대(TimeZone) 기준의 Calendar 객체 얻기

 

    • 다른 시간대의 Calendar 객체 얻기

 

    • 날짜 및 시간 정보 얻기

 

Calendar는 추상 클라싀 이므로 인스턴스를 생성할 수 없다.

 

운영체제의 시간대를 기준으로 Calendar얻기

public class CalendarExample {

           public static void main(String[] args) {

                       Calendar now = Calendar.getInstance();

 

                       int year = now.get(Calendar.YEAR);

                       int month = now.get(Calendar.MONTH) + 1;

                       int day = now.get(Calendar.DAY_OF_MONTH);

                       int week = now.get(Calendar.DAY_OF_WEEK);

 

                       String strWeek = null;

                       switch (week) {

                       case Calendar.MONDAY:

                                  strWeek = "";

                                  break;

                       case Calendar.TUESDAY:

                                  strWeek = "";

                                  break;

                       case Calendar.WEDNESDAY:

                                  strWeek = "";

                                  break;

                       case Calendar.THURSDAY:

                                  strWeek = "";

                                  break;

                       case Calendar.FRIDAY:

                                  strWeek = "";

                                  break;

                       case Calendar.SATURDAY:

                                  strWeek = "";

                                  break;

                       default:

                                  strWeek = "";

                       }

 

                       int amPm = now.get(Calendar.AM_PM);

                       String strAmPm = null;

                       if (amPm == Calendar.AM) {

                                  strAmPm = "오전";

                       } else {

                                  strAmPm = "오후";

                       }

 

                       int hour = now.get(Calendar.HOUR);

                       int minute = now.get(Calendar.MINUTE);

                       int second = now.get(Calendar.SECOND);

 

                       System.out.print(year + " ");

                       System.out.print(month + " ");

                       System.out.println(day + " ");

                       System.out.print(strWeek + "요일 ");

                       System.out.println(strAmPm + " ");

                       System.out.print(hour + " ");

                       System.out.print(minute + " ");

                       System.out.println(second + " ");

           }

}

 

Calendar 클래스의 오버로딩된 다른 getInstance() 메서드를 이용하게 되면 미국/로스앤젤레스의 현재 날짜 같은 다른 시간대의 Calendar를 얻을 수 있습니다. 알고 싶은 시간대의 java.util.TimeZone 객체를 얻어

Calendar.getInstance() 메서드의 매개값으로 넘겨주면 됩니다.

ex)

TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");

Calendar now = Calendar.getInstance(tz);

TimeZone.getTimeZone() 메서드의 매개값은 TimeZone 클래스의 static 메서드은 getAvailableIDs()를 호출하여 얻은 시간대 문자열 중에서 하나를 골라 사용하면 됩니다. 이 메서드의 리턴타입은 String 배열입니다


사용 가능한 시간대 문자열 출력

public class PrintTimeZoneID {

           public static void main(String[] args) {

                       String[] availableIDs = TimeZone.getAvailableIDs();

                       for (String id : availableIDs) {

                                  System.out.println(id);

                       }

           }

}

 

11.15 Format 클래스

v  형식(Format) 클래스

숫자와 날짜를 원하는 형식의 문자열로 변환

종류

      숫자 형식: DecimalFormat

      날짜 형식: SimpleDateFormat

      매개변수화 된 문자열 형식: MessageFormat

11.5.1숫자 형식 클래스(DecimalFormat)

적용할 패턴 선택해 생성자 매개값으로 지정 후 객체 생성

 

 

 

 

숫자를 원하는 형식으로 출력

public class DecimalFormatExample {

           public static void main(String[] args) {

                       double num = 1234567.89;

                      

                       DecimalFormat df = new DecimalFormat("0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("0.0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("0000000000.00000");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("#");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("#.#");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("##########.#####");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("#.0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("+#.0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("-#.0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("#,###.0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("0.0E0");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("+#,### ; - #,###");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("#.# %");

                       System.out.println(df.format(num));

                      

                       df = new DecimalFormat("\u00A4 #,###");

                       System.out.println(df.format(num));

           }

}

 

11.5.2 날짜 형식 클래스(SimpleDateFormat)

 

날짜를 원하는 형식으로 출력

public class SimpleDateFormatExample {

           public static void main(String[] args) {

                       Date now = new Date();

                      

                       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

                       System.out.println(sdf.format(now));

                      

                       sdf = new SimpleDateFormat("yyyy MM dd");

                       System.out.println(sdf.format(now));

                      

                       sdf = new SimpleDateFormat("yyyy.MM.dd a HH:mm:ss");

                       System.out.println(sdf.format(now));

                      

                       sdf = new SimpleDateFormat("오늘은 E요일");

                       System.out.println(sdf.format(now));

                      

                       sdf = new SimpleDateFormat("올해의 D번째 날");

                       System.out.println(sdf.format(now));

                     

                       sdf = new SimpleDateFormat("이달의 d번째 날");

                       System.out.println(sdf.format(now));

           }

}

 

11.15.3 매개변수화 된 문자열 형식 클래스(MessageFormat)

데이터를 파일에 저장하거나, 네터워크로 전송할 때, 또는 데이터베이스 SQL 문을 작성할 때

등 많은 부분에서 일정한 형식의 문자열을 사용합니다. MessageFormat 클래스를 사용하면 문자열에 데이터가 들어갈 자리를 표시해 두고, 프로그램이 실행하면서 동적으로 데이터를 삽입해 문자열을 완성시킬 수 있습니다.예를 들어서 아래와 같은 회원 정보를 출력한다고 하면,

userId : blue

userName : 신용권

userTel : 010-123-1234

 

userId, userName, userTel 이라는 변수에 회원 정보가 저장되어 있다면, 아래와 같은 + 연산자로 출력할  문자열을 생성할 수 있을 것입니다

String inf = "회원 Id" +userId+ "회원 이름" +userName + "회원 전화번호" + userTel; 

나쁜 방법은 아니지만 + 연산자 때문에 복잡해 보이고 전체 문자열을 파악하기 쉽지 않습니다.

아래와 같이 MessageFormat 클래스를 사용하면 좀 더 깔끔하게 데이터를 삽입시켜주고 전체 문자열을 쉽게 예측할 수 있습니다.

String message = "회원 Id :{0} \n회원 이름 : {1} \n회원 전화번호 : {2}";

String result = MessageFormat.format(message, userId, userName, userTel);

 

MessageFormat static format() 메서드를 호출하여 완성된 문자열을 리턴합니다

format() 메서드의 첫 번째 매개값은 매개 변수화된 문자열을 지정하고, 두 번째 이후의 매개값들은 인덱스의 순서에 맞게 값을 나열하면 됩니다. 값 대신 아래 처럼 배열을 대입해도 됩니다.

String message = "회원 Id :{0} \n회원 이름 : {1} \n회원 전화번호 : {2}";

Object[] arguments = {userId, userName, userTel};

String result = MessageFormat.format(message, arguments);


매개 변수화된 문자열 형식

public class MessageExample {

           public static void main(String[] args) {

                       String id="java";

                       String name ="신용권";

                       String tel = "010-123-5678";

                      

                       String text = "회원 id:{0} \n회원 이름: {1} \n회원 전화{2}";

                       String result1 = MessageFormat.format(text,id, name,tel);

                       System.out.println(result1);

                       System.out.println();

                      

                       String sql ="insert into member values({0},{1},{2})";

                       Object[] arguments = {"java","신용권","010-123-5678"};

                       String result2 = MessageFormat.format(sql,arguments);

                       System.out.println(result2);

           }

}

 

11.16 java.time 패키지

v  java.time 패키지

자바8부터 추가된 패키지

날짜와 시간을 나타내는 여러 가지 API가 새롭게 추가됨

날짜와 시간을 조작하거나 비교하는 기능이 추가됨

      Date Calendar는 날짜와 시간을 조작하거나 비교하는 기능이 불충분

 

 

Date 클래스의 대부분의 메서드는 Deprecated 되었고

Date의 용도는 단순히 특정 시점의 날짜 정보를 저장하는 역할만을 했습니다

Calendar 클래스는 날짜와 시간 정보를 얻기엔 충분했지만,

 날짜와 시간을 조작하거나 비교하는 기능이 불충분합니다

자바 8부터 날짜와 시간으 나타내는 여러가지 API를 새롭게 추가됐습니다.  

API java.util 패키지에 없고 별도로 java.time 패키지와 하위 패키지로 제공됩니다.

 

11.16.1 날짜와 시간 객체 생성

    • 날짜와 시간을 표현하는 5개의 클래스

 

 

날짜와 시간 객체 생성

1. LocalDate         : 로컬 날짜 클래스

 날짜 정보만을 저장할 수 있습니다. LocalDate 객체는 두 가지 static 메서드를 얻을 수 있는데 

now()는 컴퓨터의 현재 날짜 정보를 저장한 LocalDate 객체를 리턴하고 

of() 는 매개값으로 주어진 날짜 정보를 저장한 LocalDate 객체를 리턴합니다.

 

 LocalDate currDate = LocalDate.now();

 LocalDate targetDate = LocalDate.of(int year, int month, int dayOfMonth);

 

2.LocalTime         : 로컬 시간 클래스

 시간 정보만을 저장할 수 있습니다. LocalTime 객체도 마찬가지로 두 가지 static 메서드를 얻을 수 있습니다.

 now()는 컴퓨터의 현재 시간 정보를 저장한 LocalTime 객체를 리턴하고 

of() 는 매개값으로 주어진 시간 정보를 저장한 LocalTime 객체를 리턴합니다.

 

 LocalTime currTime = LocalTime.now();

 LocalTime targetTime = LocalTime.of(int hour, int minute, int second, int nanoOfSecond);

 

3. LocalDateTime   : 로컬 날짜 및 시간 클래스 (1 + 2)

 LocalDateTime LocalDate LocalTime 를 결합한 클래스라고 보면 됩니다

날짜와 시간 정보를 모두 저장할 수 있습니다

LocalDateTime 객체도 마찬가지로 두 가지 static 메서드를 얻을 수 있습니다.

now()는 컴퓨터의 현재 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴하고

 of() 는 매개값으로 주어진 날짜와 시간 정보를 저장한 LocalDateTime 객체를 리턴합니다.

 

LocalDateTime currTime = LocalDateTime.now();

 LocalDateTime targetTime = LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond);

 

4. ZonedDateTime  : 특정 타임존의  날짜와 시간 클래스

 ISO-8601 달력 시스템에서 정의하고 있는 타임존의 날짜와 시간을 저장하는 클래스입니다

저장 형태는 2016-01-08T12:56:09.017+09:00[Asia/Seoul]와 같이 

맨 뒤에 타임존에 대한 정보(+-존오프셋[존아이디]가 추가적으로 붙습니다

존오프셋 : 협정세계시(UTC)와 차이나는 시간을 말합니다.

ZonedDateTime now() static 메서드에 ZoneId를 매개값으로 주고 얻을 수 있습니다.

 ZoneId of() 메서드를 얻을 수 있는데,

 of()의 매개값은 java.util.TimeZone getAvailableIds() 메서드가 리턴하는 유효한 값 중 하나입니다.

 

ZonedDateTime utcDateTime =ZonedDateTime.now(ZonedId.of("UTC"));

ZonedDateTime londonDateTime =ZonedDateTime.now(ZonedId.of("Europe/London"));

ZonedDateTime seoulDateTime =ZonedDateTime.now(ZonedId.of("Asia/Seoul"));

 

5. Instant   : 특정 시점의 Time-Stamp 클래스

 날짜와 시간의 정보를 얻거나 조작하는데 사용되지 않고, 특정 시점의 타임스탬프로 사용됩니다.

주로 특정한 두 시점 간의 시간적 웃너순위를 따질 때 사용합니다

java.util.Date와 가장 유사한 클래스이지만

차이점은 Date는 로컬 컴퓨터의 현재 날짜와 시간 정보가 기준이지만,

 Instant는 협정세계시(UTC)를 기준으로 합니다.

 

Instant instant1 = Instant.now();

Instant instant2 = Instant.now();

if(instant1.isBefore(instant2)) { System.out.println("instant1이 빠릅니다.");}

else if(instant1.isAfter(instant2)) { System.out.println("instant2가 빠릅니다.");}

else{System.out.println("동일한 시간입니다..");}

System.out.println("차이(nanos) :" instant1.until(instant2, ChronoUnit.NANOS));


날짜와 시간 객체 생성

public class DateTimeCreateExample {

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

                       // 날짜 얻기

                       LocalDate currDate = LocalDate.now();

                       System.out.println("현재 날짜: " + currDate);

 

                       LocalDate targetDate = LocalDate.of(2024, 5, 10);

                       System.out.println("목표 날짜: " + targetDate + "\n");

 

                       // 시간 얻기

                       LocalTime currTime = LocalTime.now();

                       System.out.println("현재 시간: " + currTime);

 

                       LocalTime targetTime = LocalTime.of(6, 30, 0, 0);

                       System.out.println("목표 시간: " + targetTime + "\n");

 

                      // 날짜와 시간 얻기

                       LocalDateTime currDateTime = LocalDateTime.now();

                       System.out.println("현재 날짜와 시간: " + currDateTime);

 

                       LocalDateTime targetDateTime = LocalDateTime.of(2024, 5, 10, 6, 30, 0, 0);

                       System.out.println("목표 날짜와 시간: " + targetDateTime + "\n");

 

                       // 협정 시계시와시간존(TimeZone)

                       ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));

                       System.out.println("협정 서계시:" + utcDateTime);

                       ZonedDateTime nowyourkDateTime = ZonedDateTime.now(ZoneId.of("America/New_York"));

                       System.out.println("뉴욕 시간존:" + nowyourkDateTime + "\n");

 

                       // 특정 시점의 타임스탬프 얻기

                       Instant instant1 = Instant.now();

                       Thread.sleep(10);

                       Instant instant2 = Instant.now();

                       if (instant1.isBefore(instant2)) {

                                  System.out.println("instant1이 빠릅니다.");

                       } else if (instant1.isAfter(instant2)) {

                                  System.out.println("instant1가 늦습니다.");

                       } else {

                                  System.out.println("동일한 시간입니다.");

                       }

                       System.out.println("차이(nanos) :" + instant1.until(instant2, ChronoUnit.NANOS));

           }

}

 

11.6.2 날짜와 시간에 대한 정보 얻기

 

 

    • LocalDateTime/ZonedDateTime

      isLeapYear() toLocalDate() 메소드로 LocalDate로 변환 후 사용

      ZonedDateTime에서 제공하는 추가 메소드

 

 

날짜와 시간 정보

public class DateTimeInfoExample {

           public static void main(String[] args) {

                       LocalDateTime now = LocalDateTime.now();

                       System.out.println(now);

                      

                       String strDateTime = now.getYear() +" ";

                       strDateTime += now.getMonthValue() +" ";

                       strDateTime += now.getDayOfMonth() +" ";

                       strDateTime += now.getDayOfWeek()+" ";

                       strDateTime += now.getHour() +" ";

                       strDateTime += now.getMinute() +" ";

                       strDateTime += now.getSecond() +" ";

                       strDateTime += now.getNano() +"나노초 ";

                       System.out.println(strDateTime +"\n");

                      

                       LocalDate nowDate = now.toLocalDate();

                       if(nowDate.isLeapYear()) {

                                  System.out.println("올해는 윤년: 2월을 29일 까지 있습니다.");

                       }else {

                                  System.out.println("올해는 평년: 2월을 28일 까지 있습니다.");

                       }

                      

                       //협정 세계시와 존오프셋

                       ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));

                       System.out.println("협정 세계시 :" +utcDateTime);

                       ZonedDateTime seoulDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));

                       System.out.println("서울 타임존 :" +seoulDateTime);

                       ZoneId seoulZoneId = seoulDateTime.getZone();

                       System.out.println("서울 존아이디:" +seoulZoneId);

                       ZoneOffset seoulZoneOffSet =seoulDateTime.getOffset();

                       System.out.println("서울 존오프셋"+seoulZoneOffSet);

           }

}

 

11.16.3 날짜와 시간을 조작하기

    • 빼기와 더하기

      빼기 – minus + 변수 (long) 의 형태

Ex) minusYears(long) à 년 빼기

      더하기 – plus + 변수 (long) 의 형태

 

 

각 메소들은 수정된 LocalDate, LocalTime, LocalDateTime, ZonedDateTime을 리턴하기 때문에 도트(.) 연산자로 연결해서 순타적으로 호출할 수 있ㄷ.

 

날짜와 시간 연산

public class DateTimeOperationExample {

           public static void main(String[] args) {

                       LocalDateTime now = LocalDateTime.now();

                       System.out.println("현재시: " + now);

 

                       LocalDateTime targetDateTime = now

                                              .plusYears(1)

                                              .minusMonths(2)

                                              .plusDays(3)

                                              .plusHours(4)

                                              .minusMinutes(5)

                                              .plusSeconds(6);

 

                       System.out.println("연산후: " + targetDateTime);

           }

}

 

변경하기

 

      with(TemporalAdjuster adjuster)

현재 날짜를 기준으로 상대적 날짜 리턴

       TemporalAdjuster 객체는 아래 표에 있는 정적 메소드로 얻음

 

 

날짜와 시간 변경

public class DateTimeChangeExample {

           public static void main(String[] args) {

                       LocalDateTime now = LocalDateTime.now();

                       System.out.println("현재: " + now);

                      

                       LocalDateTime targetDateTime = null;

 

                       // 직접 변경

                       targetDateTime = now

                                              .withYear(2024)

                                              .withMonth(10)

                                              .withDayOfMonth(5)

                                              .withHour(13)

                                              .withMinute(30)

                                              .withSecond(20);

                       System.out.println("직접 변경: " + targetDateTime);

 

                       // 년도 상대 변경

                       targetDateTime = now.with(TemporalAdjusters.firstDayOfYear());

                       System.out.println("이번 해의 첫 일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.lastDayOfYear());

                       System.out.println("이번 해의 마지막 일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.firstDayOfNextYear());

                       System.out.println("다음 해의 첫 일: " + targetDateTime);

 

                       // 월 상대 변경

                       targetDateTime = now.with(TemporalAdjusters.firstDayOfMonth());

                       System.out.println("이번 달의 첫 일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.lastDayOfMonth());

                       System.out.println("이번 달의 마지막 일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.firstDayOfNextMonth());

                       System.out.println("다음 달의 첫 일: " + targetDateTime);

 

                       // 요일 상대 변경

                       targetDateTime = now.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));

                       System.out.println("이번 달의 첫 월요일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY));

                       System.out.println("돌아오는 월요일: " + targetDateTime);

                       targetDateTime = now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));

                       System.out.println("지난 월요일: " + targetDateTime);

           }

}

 

11.16.4 날짜와 시간을 비교하기

        Period: , , 일의 양을 나타내는 날짜 기준 클래스

         Duration: , , , 나노초의 양을 나타내는 시간 기준 클래스

 

 

 

Period는 년, , 일의 양을 /Duration은 시, , , 나노초의 양을 나타내느 클래스입니다

이 클래스들은 D-day D-time을 구할 때 사용할 수 있습니다

아래는 Period Duration 이 제공하는 메서드들입니다.

 

Period Duration

Period: , , 일의 양을 나타내는 날짜 기준 클래스

Duration: , , , 나노초의 양을 나타내는 시간 기준 클래스

 

 

between() 메소드의 차이점

Period Duration between()

 , , , 초의 단순 차이를 리턴

ChronoUnit between()

 전체 시간을 기준으로 차이를 리턴

 

날짜와 시간 비교
public class DateTimeCompareExample {

           public static void main(String[] args) {

                       LocalDateTime startDateTime = LocalDateTime.of(2023, 1, 1, 9, 0, 0);

                       System.out.println("시작일: " + startDateTime);

 

                       LocalDateTime endDateTime = LocalDateTime.of(2024, 3, 31, 18, 0, 0);

                       System.out.println("종료일: " + endDateTime + "\n");

 

                       // --------------------------------------------------------------

                       if (startDateTime.isBefore(endDateTime)) {

                                  System.out.println("진행 중입니다." + "\n");

                       } else if (startDateTime.isEqual(endDateTime)) {

                                  System.out.println("종료합니다." + "\n");

                       } else if (startDateTime.isAfter(endDateTime)) {

                                  System.out.println("종료했습니다." + "\n");

                       }

 

                       // --------------------------------------------------------------

                       System.out.println("[종료까지 남은 시간]");

                       long remainYear = startDateTime.until(endDateTime, ChronoUnit.YEARS);

                       long remainMonth = startDateTime.until(endDateTime, ChronoUnit.MONTHS);

                       long remainDay = startDateTime.until(endDateTime, ChronoUnit.DAYS);

                       long remainHour = startDateTime.until(endDateTime, ChronoUnit.HOURS);

                       long remainMinute = startDateTime.until(endDateTime, ChronoUnit.MINUTES);

                       long remainSecond = startDateTime.until(endDateTime, ChronoUnit.SECONDS);

                       remainYear = ChronoUnit.YEARS.between(startDateTime, endDateTime);

                       remainMonth = ChronoUnit.MONTHS.between(startDateTime, endDateTime);

                       remainDay = ChronoUnit.DAYS.between(startDateTime, endDateTime);

                       remainHour = ChronoUnit.HOURS.between(startDateTime, endDateTime);

                       remainSecond = ChronoUnit.SECONDS.between(startDateTime, endDateTime);

                       System.out.println("남은 해: " + remainYear);

                       System.out.println("남은 달: " + remainMonth);

                       System.out.println("남은 일: " + remainDay);

                       System.out.println("남은 시간: " + remainHour);

                       System.out.println("남은 분: " + remainMinute);

                       System.out.println("남은 초: " + remainSecond + "\n");

 

                       // --------------------------------------------------------------

                       System.out.println("[종료까지 남은 기간]");

                       Period period = Period.between(startDateTime.toLocalDate(), endDateTime.toLocalDate());

                       System.out.print("남은 기간: " + period.getYears() + " ");

                       System.out.print(period.getMonths() + " ");

                       System.out.println(period.getDays() + "\n");

 

                       // --------------------------------------------------------------

                       Duration duration = Duration.between(startDateTime.toLocalTime(), endDateTime.toLocalTime());

                       System.out.println("남은 초: " + duration.getSeconds());

 

           }

}



11.16.5 파싱과 포맷팅

    • 파싱: 주어진 문자열로 날짜와 시간을 생성
    • 포맷팅: 날짜와 시간을 형식화된 문자열로 변환
  • 파싱(Parsing) 메소드 (p.563~565)
    • 상황에 맞는 포맷 변환 같이 사용

 

v  포맷팅(Formatting) 메소드

날짜와 시간을 포맷팅된 문자열로 변환

 LocalDate parse(CharSequence) 메서드는 기본적으로 ISO_LOCAL_DATE 포맷터를 사용해서 문자열을 파싱합니다. ISO_LOCAL_DATE DateTimeFormatter의 상수로 정의되어 있는데

"2024-05-03" 형식의 포맷터입니다.

LocalDate localdate = LocalDate.parse("2024-05-31");

만약 다른 포맷터를 이용해서 문자열을 파싱하고 싶다면 parse(CharSequence, DateTimeFormatter)메서드를 사용할 수 있습니다. DateTimeFormatter ofPattern() 메서드로 정의할 수도 있는데 아래 코드는 "2024.05.31" 형식의 DateTimeFormatter를 정의하고 문자열을 파싱합니다.

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy.MM.dd");

LocalDate ld = LocalDate.parse("2024.05.31", dtf);

 

아래 표는 ofPattern() 메서드의 매개값으로 사용되는 패턴 기호에 대한 설명은 아래 사이트의 http://docs.oracle.com/javase/8/docs/api/ Pattern for Formartting and Parsing이란 제목으로 잘 나와있습니다.

 

 DateTimeFormatter에는 표준화된 포맷터들이 상수로 미리정해져 있기 때문에 ofPattern() 메서드를 사용하지 않고 바로 이용할 수 있습니다.


문자열 파싱

       public static void main(String[] args) {

                       DateTimeFormatter formatter;

                       LocalDate localDate;

 

                       localDate = LocalDate.parse("2024-05-21");

                       System.out.println(localDate);

 

                       formatter = DateTimeFormatter.ISO_LOCAL_DATE;

                       localDate = LocalDate.parse("2024-05-21", formatter);

                       System.out.println(localDate);

 

                       formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

                       localDate = LocalDate.parse("2024/05/21", formatter);

                       System.out.println(localDate);

 

                       formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");

                       localDate = LocalDate.parse("2024.05.21", formatter);

                       System.out.println(localDate);

           }

}

 

포맷팅 문자열

public class DateTimeFormatExample {

           public static void main(String[] args) {

                       LocalDateTime now = LocalDateTime.now();

                       DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy M d a h m");

                       String nowString = now.format(dateTimeFormatter);

                       System.out.println(nowString);

           }

}

 

확인문제

 

1. Object 클래스에 대한 설명 중 틀린 것은 무엇입니까?

* 1. 모든 자바 클래스의 최상위는 부모 클래스이다.

   * 2. Object equals() 메소드는 == 연산자와 동일하게 번지를 비교한다.

   * 3. Object clone() 메소드는 얕은 복사를 한다.

   * 4. Object toString() 메소드는 객체의 필드값을 문자열로 리턴한다.

   *    (X, Object toString은 객체의 생성번지를 이용해서 해시코드를 만든다음에, 그 해시코드의 문자열을 리턴하도록 되어있다.

   *     기본적으로 형식은 "클래스명@16진수해시코드" 로 구성된 문자 정보를 리턴하도록 되어있다.)

 

 

true

같음

2. 여러분이 작성하는 클래스를 동등 비교하는 컬렉션 객체인 HashSet, HashMap, Hashtable을 사용하려고 합니다.Objectequals()hashCode()메소드를 오버라이딩 했다고 가정할 경우 , 메소드 호출 순서를 생각하고 다음 괄호 ()안을 채워보세요

 

 

 

 

 

 

3. Student 클래스를 작성하되 Object equals() hashCode()를 오버라이딩 해서 Student의 학번(studentNum) 이 같으면 동등객체가 될 수 있도록 해보세요. Student 클래스의 필드는 다음과 같습니다. hashCode()의 리턴 값은 studentNum 필드값의 해시코드를 리턴하도록 하세요.

package textbook.chapter11.excersize;

 

public class Student {

           private String studentNum;

          

           public Student(String studentNum) {

               this.studentNum = studentNum;

             }

 

             public String getStudentNum() {

               return studentNum;

             }

 

             @Override

             public boolean equals(Object object) {

               if(object instanceof Student) {

                 Student student = (Student) object;

                 if(studentNum.equals(student.getStudentNum())) {

                   return true;

                 }

               }

               return false;

             }

 

             @Override

             public int hashCode() {

               return studentNum.hashCode();

             }

          

}

 

package textbook.chapter11.excersize;

 

import java.util.HashMap;

 

public class StudentExample {

           public static void main(String[] args) {

                       //student키로 충점을 저장한느 HashMap 객체 생성

                       HashMap<Student, String> hashMap = new HashMap<>();

                      

                       //new Student("1") 의 점수 95를 저장

               hashMap.put(new Student("1"), "95");

 

               //new Student("1") 로 점수를 읽어옴

               String score = hashMap.get(new Student("1"));

               System.out.println("1번 학생의 총점: " + score);

           }

}

 

4.Member클래스를 작성하되 ,ObjecttoString(_)메소드를 오버라이딩해서 MemberExample클래스의 실행결과처럼 나오도록 작성해보세요.

public class Member {

           private String id;

           private String name;

          

           public Member(String id, String name) {

                       this.id = id;

                       this.name= name;

           }

 

           @Override

           public String toString() {

                       return id + ": " + name ;

           }

}

 

package textbook.chapter11.excersize;

 

public class MemberExample {

           public static void main(String[] args) {

                       Member member = new Member("blue","이파란");

                       System.out.println(member);

           }

}

 

5. Class 객체에 대한 설명 중 틀린 것은 무엇입니까?

1. Class.forName() 메소드 또는 객체의 getClass() 메소드로 얻을 수 있다.

2. 클래스의 생성자, 필드, 메소드에 대한 정보를 알아낼 수 있다.

3. newInstance() 메소드는 기본 생성자를 이용해서 객체를 생성시킨다.

4. newInstance() 의 리턴 타입은 생성된 객체의 클래스 타입이다.

(x, 아니다. newInstance() 메소드의 리턴타입은 Object이기 때문에, 원래 클래스 타입으로 강제 타입변환을 해야한다.

하지만, 클래스 타입을 모르는 상태이므로 변환을 할 수가 없는데, 이 문제를 해결하려면 인터페이스 사용이 필요하다.)

 

6.다음에 주어진 바이트 배열을 문자열로 변환시켜보세요

{73,32,108,111,118,101,32,121,111,117}

package textbook.chapter11.excersize;

 

public class BytesToStringExample {

           public static void main(String[] args) {

                       byte[] bytes = {73,32,108,111,118,101,32,121,111,117};

                       String str = new String(bytes);

                       System.out.println(str);

           }

}

 

7. 다음 문자열에서 "자바" 문자열이 포함되어 있는지 확인하고 "자바" Java로 대치한 새로운 문자열을 만들어보세요.

"모든 프로그램은 자바 언어로 개발될 수 있다.";

package textbook.chapter11.excersize;

 

public class FindAndReplaceExample {

           public static void main(String[] args) {

                       String str ="모든 프로그램은 자바 언어로 개발될 수 있다.";

                       int index = str.indexOf("자바");

                       if(index == -1) {

                                  System.out.println("자바 문자열이 포함되어 있지 않습니다.");

                       }else {

                                  System.out.println("자바 문자열이 포함되어 있습니다.");

                                  str = str.replace("자바", "java");

                                  System.out.println("->"+str);

                       }

           }

}

 

8. 다음 문자열에서 쉼표(,) 로 구분되어 있는 문자열을 Stringsplit()메소드 또는 StringTokenizer를 이용해서 분리해보세요

아이디,이름,패스워드

 

package textbook.chapter11.excersize;

 

import java.util.StringTokenizer;

 

 

public class SplitExample {

           public static void main(String[] args) {

                       String str ="아이디,이름,패스워드";

                      

                       //밥법1 (split()메소드 이용)

                       String[] tokens = str.split(",");

                       for(String token: tokens) {

                                  System.out.println(token);

                       }

                       System.out.println();

                      

                       //방법2 (StringTokenizer이용)

                       StringTokenizer st = new StringTokenizer(str,",");

                       int countTokens = st.countTokens();

                       for(int i = 0; i <countTokens ; i++) {

                                  String token = st.nextToken();

                                  System.out.println(token);

                       }

           }

}

 

9. 다음 코드는 1부터 100까지의 숫자를 통 문자열로 만들기위해서 += 연산자를 이용해서 100번 반복하고 있습니다.

이것은 곧 100개 이상의 String 객체를 생성하는 결과를 만들기 때문에 좋은 코드라고 볼 수 없습니다.

StringBulider를 사용해서 좀 더 효율적인 코드로 개선시켜보세요.

package textbook.chapter11.excersize;

 

public class StringBuilderExample {

           public static void main(String[] args) {

                       String str="";

                       for(int i = 1; i <= 100; i++) {

                                  str+= i;

                       }

                       System.out.println(str);

                      

                       //개선 코드 작성 위치

                       StringBuilder sb = new StringBuilder();

                       for(int i = 1; i <= 100; i++) {

                                  sb.append(i);

                       }

                       str=sb.toString();

                       System.out.println(str);

           }

}

 

10첫 번째 알파벳으로 시작하고 두번째 부터 숫자와 알파벳으로 구선된 8~12자 사이의 ID값인지 검사하고 싶습니다. 알파벳은 대소문자를 모두 허용할 경우에 정규표현식을 이용해서 검증하는 코드를 작성해보세요

package textbook.chapter11.excersize;

 

import java.util.regex.Pattern;

 

public class PatternMatcherExample {

           public static void main(String[] args) {

                       String id ="5Angel1004";

                       String regExp="[a-zA-Z][a-zA-Z0-9]{7,11}";

                       boolean isMatch = Pattern.matches(regExp, id);

                       if(isMatch) {

                                  System.out.println("ID로 사용할 수 있습니다.");

                       }else {

                                  System.out.println("ID로 사용할 수 없습니다.");

                       }

           }

}

 

 

11. 숫자 100 300으로 각각 박싱된 Integer객체를 == 연산자로 비교했습니다. 100을 박싱한 Integer 객체는 true가 나오는데, 300을 박싱한 Integer 객체는 false가 나오는 이유를 설명해보세요.

=> Wrapper Class Integer Class -128 ~ 127 사이의 숫자는 ==으로 내부의 값응ㄹ 비교할 수 있다.

따라서 100은 범위안에 해당하므로 비교가 가능해서 true값을 반환한다.

Integer의 경우 -128 ~ 127 의 범위를 넘는 숫자는 ==으로 비교할 수 없고,

포장 클래스의 내부 값을 비교하도록 오버라이딩 된 equals() 메소드로 비교해야 한다.

package textbook.chapter11.excersize;

 

public class IntegerCompareExample {

           public static void main(String[] args) {

                       Integer obj1 = 100;

               Integer obj2 = 100;

               Integer obj3 = 300;

               Integer obj4 = 300;

              

               System.out.println(obj1 == obj2);

               System.out.println(obj3 == obj4);

               System.out.println(obj3.equals(obj4));

           }

}

 

12.문자열 "200"을 정수로 변환하는 코드와 숫자 150을 문자열로 변환하는 코드를 작성해보세요

package textbook.chapter11.excersize;

 

public class StringConvertExample {

           public static void main(String[] args) {

                       String strData1= "200";

                       int intData1 = Integer.parseInt(strData1);

                      

                       int intData2 = 150;

                       String strData2 = String.valueOf(intData2);

           }

}

 

 

 

 

13.SimpleDateFormat클래스를 이용해서 오늘의 날짜를 다음과 같이 출력하는 코드를 작성해보세요

2024508일 화요일 1030

package textbook.chapter11.excersize;

 

import java.text.SimpleDateFormat;

import java.util.Date;

 

public class DatePrintExample {

           public static void main(String[] args) {

                       Date now = new Date();

                       //여기서 코드를 작성하게요

                       SimpleDateFormat sdf= new SimpleDateFormat("yyyy  MM dd E요일 HH mm");

                       System.out.println(sdf.format(now));

           }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

13. 제네릭 14. 람다식  (0) 2020.10.10
12. 멀티 스레드  (0) 2020.10.03
10. 예외처리  (0) 2020.10.01
09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
08. 인터페이스  (0) 2020.09.30
반응형

출처 : 이것이 자바다

예외처리

10.1 예외와 예외 클래스

v  오류의 종류

에러(Error)

      하드웨어의 잘못된 동작 또는 고장으로 인한 오류

      에러가 발생되면 프로그램 종료

      정상 실행 상태로 돌아갈 수 없음

예외(Exception)

      사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류

      예외가 발생되면 프로그램 종료

      예외 처리 추가하면 정상 실행 상태로 돌아갈 수 있음

v  예외의 종류

일반(컴파일 체크) 예외(Exception)

      예외 처리 코드 없으면 컴파일 오류 발생

      Exception을 상속 받지만 RuntimeException을 상속받지 않는 클래스들

실행 예외(RuntimeException)

      예외 처리 코드를 생략하더라도 컴파일이 되는 예외

      경험 따라 예외 처리 코드 작성 필요

      RuntimeException을 상속받은 클래스들이다.

v  예외 클래스

 

 

10.2 실행 예외(RuntimeException)

실행 예외는 자바 컴파일러가 체크를 하지 않기 때문에 오로지 개발자의 경험에 의해서 예외 처리 코드를 삽입해야 한다.

처리하지 않을 경우 예외가 발생하면 프로그램은 곧바로 종료된다.

10.2.1 NullPointerException

객체 참조가 없는 상태

null 값 갖는 참조변수로 객체 접근 연산자인 도트(.) 사용했을 때 발생

 

 

객체가 없는 상태에서 객체를 사용하려 했으니 예외가 발생하는 것이다.

 

NullPointerException이 발생하는 경우

public class NullPointerExceptionExample {

           public static void main(String[] args) {

                       String data = null;

                       System.out.println(data.toString());

           }

}

 

10.2.2 ArrayIndexOutOfBoundsException

배열에서 인덱스 범위 초과하여 사용할 경우 발생

 

 

 

 

 

 

 

 

ArrayIndexOutOfBoundsExceptionExample

public class ArrayIndexOutOfBoundsExceptionExample {

           public static void main(String[] args) {

                       String data1 = args[0];

                       String data2 = args[1];

 

                       System.out.println("args[0]: " + data1);

                       System.out.println("args[1]: " + data2);

           }

}

 

args를 선언하지 않았기 때문에 예외가 발생한다.

이 문제를 해결할려면 [Run] ->[Run Configurations] ->[Arguments] ->[Program arguments]

두 개의 매개값을 입력하고 실행하면 예외가 발생하지 않는다.

 

배열값을 읽기 전에 배열의 길이를 먼저 조사하는 것이  좋다.

ArrayIndexOutOfBoundsExceptionExample

public class ArrayIndexOutOfBoundsExceptionExample {

           public static void main(String[] args) {

                       if(args.length ==2) {

            String data1 = args[0];

            String data2 = args[1];

            System.out.println("args[0]: " + data1);

            System.out.println("args[1]: " + data2);

        } else {

            System.out.println("[실행 방법]");

            System.out.println("java ArrayIndexOutOfBoundsExceptionExample");

            System.out.println("1 2");

        }

           }

}

 

10.2.3 NumberFormatException

 

Integer Double은 포장(Wrapper) 클래스라고 하는데, 이 클래스의 정적 메소드인 parseXXX() 메소드를 이용하면 문자열을 숫자로 변환할 수 있다.

 

이 메소드들은 매개값인 문자열이 숫자로 변환될 수 있다면 숫자를 리턴하지만, 숫자로 변환될 수 없는 문자가 포함되어 있다면 java.lang.NumberFormatException을 발생시킨다.

NumberFormatException이 발생하는 경우

public class NumberFormatExceptionExample {

           public static void main(String[] args) {

        String data1 = "100";

        String data2 = "a100";

       

        int value1 = Integer.parseInt(data1);

        int value2 = Integer.parseInt(data2);    //NumberFormatException 발생

       

        int result = value1 + value2;

        System.out.println(data1 + "+" + data2 + "=" + result);

    }

}

 

10.2.4 ClassCastException

타입 변환이 되지 않을 경우 발생

 

 

 

 

 

 

 

정상 코드

 

 

예외코드

 

 

instanceof연산의 결과가 true일 경우 처리하는 것이좋다.

Animal animal = new Dog();

if(animal instanceof Dog){

  Dog dog = (Dog) animal;

}else if(animal instanceof Cat){

  Cat cat = (Cat) animal;

}

Remocon rc = new Audio();

if(rc instanceof Television){

  Television tv = (Television)rc;

}else if( rc instanceof Audio){

  Audio audio = (Audio)rc;

}

 

ClassCastException

public class ClassCastException {

           public static void main(String[] args) {

                       Dog dog = new Dog();

                       changeDog(dog);

                      

                       Cat cat = new Cat();

                       changeDog(cat);

           }

 

           private static void changeDog(Animal animal) {

                       Dog dog = (Dog) animal;//ClassCastException 발생 가능

           }

          

}

class Animal{}

class Dog extends Animal{}

class Cat extends Animal{}

 

수정후

public class ClassCastException {

           public static void main(String[] args) {

                       Dog dog = new Dog();

                       changeDog(dog);

                      

                       Cat cat = new Cat();

                       changeDog(cat);

           }

 

           private static void changeDog(Animal animal) {

                       if(animal instanceof Dog) {

                                  Dog dog = (Dog) animal;//ClassCastException 발생 가능

                       }

                      

           }

          

}

class Animal{}

class Dog extends Animal{}

class Cat extends Animal{}

 

10.3 예외 처리 코드

    • 예외 발생시 프로그램 종료 막고, 정상 실행 유지할 수 있도록 처리

      일반 예외: 반드시 작성해야 컴파일 가능

      실행 예외: 컴파일러가 체크해주지 않으며 개발자 경험 의해 작성

    • try catch finally 블록 이용해 예외 처리 코드 작성

 

 

 

 

 

일반 예외 처리

public class TryCatchFinallyExample {

           public static void main(String[] args) {

                       try {

                                  Class clazz = Class.forName("java.lang.String2");

                       } catch (ClassNotFoundException e) {

                                  System.out.println("클래스가 존재하지 않습니다.");

                       }

    }

}

 

 

 10.4 예외 종류에 따른 처리 코드

10.4.1 다중 catch

try{}

catch(){}

catch(){}

public class CatchByExceptionKindExample {
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("실행 매개값의 수가 부족합니다.");
            System.out.println("[실행 방법]");
            System.out.println("java CatchByExceptionKindExample num1 num2");
        } catch (NumberFormatException e) {
            System.out.println("숫자로 변환할 수 없습니다.");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
}

실행 매개값의 수가 부족합니다.

[실행 방법]

java CatchByExceptionKindExample num1 num2

다시 실행하세요.

 

10.4.2 catch 순서

상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 한다.

차례대로  검색된다. 

public class CatchOrderExample {
 
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("실행 매개값의 수가 부족합니다.");
        } catch (Exception e) {
            System.out.println("실행에 문제가 있습니다.");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
 
}
 

실행 매개값의 수가 부족합니다.

다시 실행하세요.

 

10.4.3 멀티 catch

 | 로 연결하면 된다.

public class MultiCatchExample {
 
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException|NumberFormatException e) {
            System.out.println("실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.");
        } catch (Exception e) {
            System.out.println("알수 없는 예외 발생");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
}
 

실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.

다시 실행하세요.

 

10.5 자동 리소스 닫기

 자바 7에서 새로 추가된 try-with-resources를 사용하면 예외 발생 여부와 상관없이 사용했던 리소스 객체(각종 입출력 스트림,서버소켓,소켓,각종 채널)의 close() 메소드를 호출해서 안전하게 리소스를 닫아준다.

 

리소스란 여러 가지 의미가 있겠지만 여기서는 데이터를 읽고 쓰는 객체라고 생각한다. 

 

try-with-resources를 사용하기 위해서는 조건이 있다

 

리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현하고 있어야 한다.

 

public class FileInputStream implements AutoCloseable{
    private String file;
    
    public FileInputStream(String file) {
        this.file =file;
    }
    
    public void read() {
        System.out.println(file + "을 읽습니다.");
    }
 
    @Override
    public void close() throws Exception {
        System.out.println(file + "을 닫습니다.");
    }
}
public class TryWithResourceExample {
 
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("file.txt")) {
            fis.read();
            throw new Exception(); // 강제적으로 예외 발생
        } catch (Exception e) {
            System.out.println("예외 처리 코드가 실행되었습니다.");
        }
    }
 
}

file.txt을 읽습니다.

file.txt을 닫습니다.

예외 처리 코드가 실행되었습니다.

 

10.6 예외 떠넘기기

메소드 내부에서 예외가 발생할 수 있는 코드를 작성할 때 try-catch 블록으로 예외를 처리하는 것이 기본이지만, 경우에 따라서는 메소드를 호출한 곳으로 예외를 떠넘길 수도 있다. 이때 사용 하는 키워드가 throws이다.

throws 키워드는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할을 한다.

다음 예제에서 Class.forName() 메소드를 사용하는 findClass() 메소드는 예외를 떠넘겼고, findClass()를 호출하는 main() 메소드에서 try-catch 블록을 사용해서 예외 처리를 했다.

public class ThrowsExample {
 
    public static void main(String[] args) {
        try {
            findClass();
        } catch (ClassNotFoundException e) {
            System.out.println("클래스가 존재하지 않습니다.");
        }
    }
 
    public static void findClass() throws ClassNotFoundException {
        Class clazz = Class.forName("java.lang.String2");
    }
}

클래스가 존재하지 않습니다.

 

10.7 사용자 정의 예외와 예외 발생

10.7.1 사용자 정의 예외 클래스 선언

일반 예외로 선언시 Exception을 상속하면 되고 , 실행 예외로 선언시 RuntimeException을 상속하면 된다.

public class BalanceInsufficientException extends Exception{
    public BalanceInsufficientException() { }
    public BalanceInsufficientException(String message) {
        super(message);
    }
}

10.7.2 예외 발생시키기

다음 예제는 은행 계좌 (Account) 클래스를 작성한 것이다. 출금(withdraw) 메소드에서 잔고(balance) 필드와 출금액을 비교해서 잔고가 부족하면 BalanceInsufficientException을 발생 시키도록 했다.

public class Account {
    private long balance;
    
    public Account() { }
    
    public long getBalance() {
        return balance;
    }
    
    public void deposit(int money) {
        balance += money;
    }
    
    public void withdraw(int money) throws BalanceInsufficientException {    //사용자 예외 떠넘기기
        if(balance < money) {
            throw new BalanceInsufficientException("잔고부족:"+(money-balance)+" 모자람");    //사용자 정의 예외 발생
        }
        balance -= money;
    }
}
 

 

10.8 예외 정보 얻기

public class AccountExample {
 
    public static void main(String[] args) {
        Account account = new Account();
        //예금하기
        account.deposit(10000);
        System.out.println("예금액: " + account.getBalance());
        //출금하기
        try {
            account.withdraw(30000);
        } catch (BalanceInsufficientException e) {    //예외 메시지 얻기
            String message = e.getMessage();
            System.out.println(message);
            System.out.println();                    //예외 추적 후 출력
            e.printStackTrace();
        }
    }
 
}

예금액: 10000

잔고부족:20000 모자람

 

sec10_7.BalanceInsufficientException: 잔고부족:20000 모자람

    at sec10_7.Account.withdraw(Account.java:18)

    at sec10_7.AccountExample.main(AccountExample.java:12)

 

getMessage() 메소드의 리턴값을 출력한 것이다.

 

연습문제

1. 예외에 대한 설명 중 틀린 것은 무엇입니까? (4)

 

1.예외는 사용자의 잘못된 조작, 개발자의 잘못된 코딩으로 인한 프로그램 오류를 말한다.

2.RuntimeException의 하위 예외는 컴파일러가 예외 처리 코드를 체크하지 않는다.

3.예외는 try-catch 블록을 사용해서 처리된다.

4.자바 표준 예외만 프로그램에서 처리할 수 있다.

 

2. try-catch-finally 블록에 대한 설명 중 틀린 것은 무엇입니까? (3)

 

1.try { } 블록에는 예외가 발생할 수 있는 코드를 작성한다.

2.catch { } 블록은 try { } 블록에서 발생한 예외를 처리하는 블록이다.

3.try { } 블록에서 return문을 사용하면 finally { } 블록은 실행되지 않는다.

4.catch { } 블록은 예외의 종류별로 여러 개를 작성할 수 있다.

 

3. throws에 대한 설명으로 틀린 것은 무엇입니까? (4)

 

1.생성자나 메소드의 선언 끝 부분에 사용되어 내부에서 발생된 예외를 떠넘긴다.

2.throws 뒤에는 떠넘겨야 할 예외를 쉼표(,)로 구분해서 기술한다.

3.모든 예외를 떠넘기기 위해 간단하게 throws Exception으로 작성할 수 있다.

4.새로운 예외를 발생시키기 위해 사용된다.

 

4. throw에 대한 설명으로 틀린 것은 무엇입니까? (2)

 

1.예외를 최초로 발생시키는 코드이다.

2.예외를 호출한 곳으로 떠넘기기 위해 메소드 선언부에 작성된다.

3.throw로 발생된 예외는 일반적으로 생성자나 메소드 선언부에 throws로 떠넘겨진다.

4.throw 키워드 뒤에는 예외 객체 생성 코드가 온다.

 

 

5. 다음과 같은 메소드가 있을 때 예외를 잘못 처리한 것은 무엇입니까? (3)

 

public void method1() throws NumberFormatException, ClassNotFoundException { ...}

 

1.try { method1();} catch(Exception e) { }

2.void method2() throws Exception {method1();}

3.try {method3();} catch (Exception e) { } catch (ClassNotFoundException e) { }

4.try {method1();} catch (ClassNotFoundException e) { } catch (NumberFormatException e) { }

 

 

 

6. 다음 코드가 실행되었을 때 출력 결과는 무엇입니까?

package sec10_7;

 

public class TryCatchFinallyExample {

 

    public static void main(String[] args) {

        String[] strArray = {"10","2a"};

        int value = 0;

        for (int i = 0; i <=2; i++) {

            try {

                value = Integer.parseInt(strArray[i]);

            } catch (ArrayIndexOutOfBoundsException e) {

                System.out.println("인덱스를 초과했음");

            } catch (NumberFormatException e) {

                System.out.println("숫자로 변환할 수 없음");

            } finally {

                System.out.println(value);

            }

        }

    }

 

}

 

10

숫자로 변환할 수 없음

10

인덱스를 초과했음

10

 

 

 

 

 

7. 로그인 기능을 Member 클래스의 login () 메소드에서 구현하려고 합니다. 존재하지 않는 ID를 입력했을 경우 NotExistIDException을 발생시키고, 잘못된 패스워드를 입력했을 경우 WrongPasswordException을 발생시키려고 합니다. LoginExample의 실행 결과를 보고 빈칸을 채워보세요.

package sec10_7;

 

public class NotExistIDException extends Exception{

    public NotExistIDException() { }

    public NotExistIDException(String message) {

        super(message);

    }

}

package sec10_7;

 

public class WrongPasswordException extends Exception{

    public WrongPasswordException() { }

    public WrongPasswordException(String message) {

        super(message);

    }

}

 

package sec10_7;

 

public class LoginExample {

    public static void main(String[] args) {

        try {

            login("white","12345");

        } catch (Exception e) {

            System.out.println(e.getMessage());

        }

        

        try {

            login("blue","54321");

        } catch (Exception e) {

            System.out.println(e.getMessage());

        }

    }

    

    public static void login(String id,String password) throws NotExistIDException,WrongPasswordException{

        //id가 "blue"가 아니라면 NotExistIDException 발생시킴

        if(!id.equals("blue")) {

            throw new NotExistIDException("아이디가 존재하지 않습니다.");

 

        }

        

        //password가 "12345"가 아니라면 WrongPasswordException 발생시킴

        if(!password.equals("12345")) {

            throw new WrongPasswordException("패스워드가 틀립니다.");

        }

    }

}

 

아이디가 존재하지 않습니다.

패스워드가 틀립니다.

반응형

' > 이것이 자바다' 카테고리의 다른 글

12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
08. 인터페이스  (0) 2020.09.30
07. 상속  (0) 2020.09.29
반응형

출처 : 이것이 자바다

중첩 클래스와 중첩 인터페이스

9.1 중첩 클래스와 중첩 인터페이스란

중첩 클래스와 중첩 인터페이스란?

중첩 클래스: 클래스 멤버로 선언된 클래스

 

중첩 인터페이스: 클래스 멤버로 선언된 인터페이스

      UI 컴포넌트 내부 이벤트 처리에 많이 활용

 

 

안드로이드에서

public class View{

           public interface OnClickListener{

                       public void onClick(View v);

}

}

 

9.2 중첩 클래스

v  중첩 클래스의 분류

 

클래스 생성시 바이트 코드 따로 생성

 

9.2.1 인스턴스 멤버 클래스

인스턴스 멤버 클래스는 static 키워드 없이 선언된 클래스

인스턴스 필드와 메소드만 선언이 가능하고 정적 필드와 메소드는 선언할 수 없다.

 

 

 

 

9.2.2 정적 멤버 클래스

    • static 키워드로 선언된 클래스, 모든 종류의 필드, 메소드 선언 가능

 

9.2.3로컬 클래스 – 메소드 내에서만 사용

 

 

 

중첩 클래스

/** 바같 클래스*/

public class A {

           A() {System.out.println("A 객체가 생성됨"); }

   

    /**인스턴스 멤버 클래스**/

    class B {

        B() {System.out.println("B 객체가 생성됨");}

        int filed1;

        void method1() { }

    }

   

    /**정적 멤버 클래스**/

    static class C {

        C() {System.out.println("C 객체가 생성됨");}

        int field1;

        static int field2;

        void method1() { }

        static void method2() { }

    }

   

    void method() {

        /**로컬 클래스**/

        class D {

            D() {System.out.println("D 객체가 생성됨");}

            int field1;

            void method1() { }

        }

        D d = new D();

        d.field1 = 3;

        d.method1();

    }

}

 

중첩 클래스 객체 생성

public class Main {

    public static void main(String[] args) {

        A a = new A();

       

        //인스턴스 멤버 클래스 객체 생성

        A.B b = a.new B();

        b.filed1 = 3;

        b.method1();

       

        //정적 멤버 클래스 객체 생성

        A.C c = new A.C();

        c.field1 = 3;

        c.method1();

        A.C.field2 = 3;

        A.C.method2();

       

        //로컬 클래스 객체 생성을 위한 메소드 호출

        a.method();

    }

}

 

9.3 중첩 클래스의 접근 제한

9.3.1 바깥 필드와 메소드에서 사용 제한

바깥 필드와 메소드에서 사용 제한

package textbook.chapter9.examl01;

 

public class A {

           // 인스턴스 필드

           B field1 = new B();

           C field2 = new C();

 

           // 인스턴스 메소드

           void method1() {

                       B var1 = new B();

                       C var2 = new C();

           }

 

           // 정적 필드 초기화

           // static B field3 = new B();

           static C field4 = new C();

 

           // 정적 메소드

           static void method2() {

                       // B var1 = new B():

                       C var = new C();

           }

 

           // 인스턴스 멤버 클래스

           class B {}

 

           // 정적 멤버 클래스

           static class C {}

}

 

9.3.2 멤버 클래스에서 사용 제한

 

 

 

 

 

멤버 클래스에서 사용 제한

package textbook.chapter9.exam02;

 

public class A {

           int field1;

    void method1() { }

   

    static int field2;

    static void method2() { }

   

    class B {

        void method() {        //모든 필드와 메소드에 접근할 수 있다.

            field1 = 10;

            method1();

           

            field2 = 10;

            method2();

        }

    }

   

    static class C {

        void method() {        //인스턴스 필드와 메소드는 접근할 수 없다.

            //field1 = 10;

            //method1();

           

            field2 = 10;

            method2();

        }

    }

}

 

멤버 클래스에서 사용 제한

 

 

9.3.3 로컬 클래스에서 사용 제한

로컬 클래스 내부에서는 바깥 클래스의 필드나 메소드를 제한 없이 사용할 수 있다.

문제는 메소드의 매개변수나 로컬 변수를 로컬 클래스에서 사용할 때이다.

결론적으로 말해서 로컬 클래스에서 사용 가능한 것은 final로 선언된 매개 변수와 로컬 변수뿐

우리는 로컬 클래스의 내부 복사 위치에 신경 쓸 필요 없이 로컬 클래스에서 사용된 매개 변수와 로컬 변수는 모두 final 특성을 갖는다는 것만 알면 된다.

자바 7까지는 반드시 final 키워드를 붙여야 되지만, 자바 8부터는 붙이지 않아도 final 특성을 가지고 있음을 주목

 

 

class LocalClass{

int arg2 = 매개값;

int var2 = 2;

void method(){

  int arg1 = 매개값;

  int var1 = 1;

  int result = arg1 +arg2+var1+var2;

}

}

void outMethod(final int arg1, int arg2){

final int var1 =1;

int var2 = 2;

class LocalClass{

  void method(){

 int result = arg1+arg2+var1+var2;

}

}

}

 

 

 

final 매개변수와 로컬 변수는

로컬 클래스의 메소드의 로컬변수로 복사

(final 붙이지 않으면 컴파일 오류 발생)

매개변수와 로컬 변수는 final 특성을 가지며,

로컬 클래스의 필드로

   
 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

로컬 클래스에서 사용 제한

public class Outter {

            //자바 7 이전

    public void method1(final int arg) {

        final int localVariable = 1;

        //arg = 100;    (x)

        //localVariable = 100; (x)

        class Inner {

            public void method() {

                int result = arg + localVariable;

            }

        }

    }

   

    //자바 8 이후

    public void method2(int arg) {

        int localVariable = 1;

        //arg = 100;     (x)

        //localVariable = 100; (x)

        class Inner {

            public void method() {

                int result = arg + localVariable;

            }

        }

    }

}

 

9.3.4 중첩 클래스에서 바깥 클래스 참조 얻기

 

 

클래스 내부에서 this는 객체 자신의 참조이다.

중첩 클래스에서 this 키워드를 사용 바깥 클래스의 객체 참조가 아니라, 중첩 클래스의 객체 참조가 된다.

따라서 중첩 클래스 내부에서 this.필드,this.메소드()로 호출하면 중첩 클래스의 메소드가 사용된다.

중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 바깥 클래스의 이름을 this 앞에 붙여주면 된다.

 

ex) 바깥클래스.this.필드

     바깥클래스.this.메소드();

 

중첩 클래스에서 바깥 클래스 참조 얻기

public class Outter {

           String field = "Outter-field";

 

           void method() {

                       System.out.println("Outter-method");

           }

 

           class Nested {

                       String field = "Nested-field";

 

                       void method() {

                                  System.out.println("Nested-method");

                       }

 

                       void print() {

                                  System.out.println(this.field); // 중첩 객체 참조

                                  this.method();

                                  System.out.println(Outter.this.field); // 바깥 객체 참조

                                  Outter.this.method();

                       }

           }

}

 

실행 클래스

public class OutterExample {

           public static void main(String[] args) {

                       Outter outter = new Outter();

                       Outter.Nested nested = outter.new Nested();

                       nested.print();

           }

}

 

9.4 중첩 인터페이스

중첩 인터페이스는 클래스의 멤버로 선언된 인터페이스를 말한다.

 

class A{

interface I{

  void method(); //중첩 인터페이스

}

}

 

중첩 인터페이스

 

 

중첩 인터페이스

public class Button {

           OnClickListener listener; // 인터페이스 타입 필드

 

           void setOnClickListener(OnClickListener listener) { // 매개 변수의 다형성

                       this.listener = listener;

           }

 

           void touch() { // 구현 객체의 onClick() 메소드 호출

                       listener.onClick();

           }

 

           interface OnClickListener { // 중첩 인터페이스

                       void onClick();

           }

}

 

구현 클래스

public class CallListener implements Button.OnClickListener {

 

           @Override

           public void onClick() {

                       System.out.println("전화를 겁니다.");

           }

}

 

 

구현 클래스

public class MessageListener implements Button.OnClickListener{

 

    @Override

    public void onClick() {

        System.out.println("메시지를 보냅니다.");

    }

 

}

 

버튼 이벤트 처리

public class ButtonExample {

           public static void main(String[] args) {

                       Button btn = new Button();

                      

                       btn.setOnClickListener(new CallListener());

                       btn.touch();

                      

                       btn.setOnClickListener(new MessageListener());

                       btn.touch();

 

           }

}

 

 

9.5 익명 객체

v  익명 객체: 이름이 없는 객체

익명 객체는 단독 생성 불가

      클래스 상속하거나 인터페이스 구현해야만 생성 가능

사용 위치

      필드의 초기값, 로컬 변수의 초기값, 매개변수의 매개값으로 주로 대입

      UI 이벤트 처리 객체나, 스레드 객체를 간편하게 생성할 목적으로 주로 활용

 

9.5.1 익명 자식 객체 생성 – 초기값 설정에 주목

class Child extends Parent{  }//자식 클래스 선언

 

class A{

Parent field = new Child(); //필드에 자식 객체를 대입

void method(){

  Parent localVar = new Child();//로컬 변수에 자식 객체를 대입

}

}

 

자식 클래스가 재사용하지 않고 , 오로지 해당 필드와 변수의 초기값으로만 사용할 경우라면 익명 자식 객체를 생성해서 초기값으로 대입하는 것이 좋은 방법이다.

주의할 점은 하나의 실행문이므로 끝에는 세미콜론(;) 을 반드시 붙여야 한다.

부모클래스 [필드|변수] = new 부모클랫(매개값, ..){

           //필드

//메소드

};

 

일반 클래스와의 차이점은 생성자를 선언할 수 없다는 것이다.

class A{

Parent field = new Child(); // A클래스의 필드 선언

int childField;

void childMethod();

@Override //Parent의 메소드를 오버라이딩

void parentMethod(){}

}

 

로컬 변수 익명 자식 객체

 

 

메소드의 매개 변수가 부모 타입일 경우 메소드 호출 코드에서 익명 자식 객체를 생성해서 매개값으로 대입할 수도 있다.

class A{

 void method1(Parent parent) { }

 

 void method2(){

method1{ //method1()메소드 호출

 new Parent(){ // method1()의 매개값으로 익명 자식 객체를 대입

  int childField;

  void childMethod() { }

  @Override

  void parentMethod(){}

}

}   

 }

}

v  익명 객체에 새롭게 정의된 필드와 메소드

익명 객체 내부에서만 사용

외부에서는 익명 객체의 필드와 메소드에 접근할 수 없음

      이유: 익명 객체는 부모 타입 변수에 대입되므로 부모 타입에 선언된 것만 사용 가능

 

 

부모 클래스

public class Person {

           void wake() {

        System.out.println("7시에 일어납니다.");

    }

}

 

익명 자식 객체 생성

public class Anonymous {

           //필드 초기값으로 대입

    Person field = new Person() {    // 필드 선언과 초기값 대입

        void work() {

            System.out.println("출근합니다.");

        }

        @Override

        void wake() {

            System.out.println("6시에 일어납니다.");

            work();

        }

    };

   

    void method1() {    //로컬 변수 선언과 초기값 대입

        //로컬 변수값으로 대입

        Person localVar = new Person() {

            void walk() {

                System.out.println("산책합니다.");

            }

            @Override

            void wake() {

                System.out.println("7시에 일어납니다.");

                walk();

            }

        };

        //로컬 변수 사용

        localVar.wake();

    }

   

    void method2(Person person) {

        person.wake();

    }

}

 

익명 자식 객체 생성

public class AnonymousExample {

           public static void main(String[] args) {

                       Anonymous anony = new Anonymous();

                       // 익명 객체 필드 사용

                       anony.field.wake();

                       // 익명 객체 로컬 변수 사용

                       anony.method1();

                       // 익명 객체 매개값 사용

                       anony.method2(new Person() {

                                  void study() {

                                              System.out.println("공부합니다.");

                                  }

 

                                  @Override

                                  void wake() {

                                              System.out.println("8시에 일어납니다.");

                                              study();

                                  }

                       });

           }

}

 

9.5.2 익명 구현 객체 생성

인터페이스 타입으로 필드나 변수를 선언하고 , 구현 객체를 초기값으로 대입하는 경우

class TV implements RemoteControl{}

 

class A{

 RemoteControl field = new TV(); //필드에 구현 객체를 대입

 void method(){

  RemoteControl localVar = new TV();//로컬 변수에 구현 객체를 대입

}

}

 

 

 

    • 초기값 설정에 대해서는 p. 409~ 416 참고

 

다음은 필드를 선언할 때 초기값으로 익명 객체를 생성해서 대입하는 예:

class A{

 RemoteControl field = new RemoteControl(){ //클래스 A의 필드 선언

   @Override   //RemoteControl 인터페이스의 추상 메소드에 대한 실체 메소드

   void turnOn() {}

 };

}

 

메스드의 매개 변수가 인터페이스 타입일 경우 , 메소드 호출 코드에서 익명 구현 객체를 생성해서 매개값으로 대입할 수도 있다.

class A{

 void method1(RemoteControl rc){}

 void method2(){

method1(){//method1 ()메소드 호출

   new RemoteControl(){//method1()의 매개값으로 익명 구현 객체를 대입

    @Override  

    void turnOn() {}

}

}

}

}

 

인터페이스

package textbook.chapter9.exam01;

 

public interface RemoteControl {

           public void turnOn();

           public void turnOff();

}

 

익명 구현 클래스와 객체 생성

package textbook.chapter9.exam01;

 

public class Anonymous {

           //필드 초기값으로 대입

           RemoteControl field = new RemoteControl() { //필드의 선언과 초기값 대입

                      

                       @Override

                       public void turnOn() {

                                  System.out.println("TV를 켭니다.");

                       }

                      

                       @Override

                       public void turnOff() {

                                  System.out.println("TV를 끕니다.");

                       }

           };

          

           void method1() { //로컬 변수 선언과 초기값 대입

                       //로컬 변수 값으로 대입

                       RemoteControl localVar = new RemoteControl() {

                                 

                                  @Override

                                  public void turnOn() {

                                              System.out.println("Aidio를 켭니다.");

                                  }

                                 

                                  @Override

                                  public void turnOff() {

                                              System.out.println("Aidio를 끕니다.");

                                  }

                       };

                      

                       //로컬 변수 사용

                       localVar.turnOn();

                      

           }

          

           void method2(RemoteControl rc) {

                       rc.turnOn();

           }

}

 

익명 구현 클래스와 객체 생성

package textbook.chapter9.exam01;

 

public class AnonymousExample {

           public static void main(String[] args) {

                       Anonymous anony = new Anonymous();

                       //익명 객체 필드 사용

                       anony.field.turnOn();

                       //익명 객체 로컬 변수 사용

                       anony.method1();

                       //익명 객체 매개값 아ㅛㅇㅇ

                       anony.method2(new RemoteControl() {//매개값

                                 

                                  @Override

                                  public void turnOn() {

                                              System.out.println("SmartTV를 켭니다.");

                                  }

                                 

                                  @Override

                                  public void turnOff() {

                                              System.out.println("SmartTV를 끕니다.");

                                  }

                       });

           }

}

 

UI클래스

package textbook.chapter9.exam01;

 

public class Button {

           OnClickListener listener; // 인터페이스 타입 필드

 

           void setOnClickListener(OnClickListener listener) { // 매개 변수의 다형성

                       this.listener = listener;

           }

 

           void touch() { // 구현 객체의 onClick() 메소드 호출

                       listener.onClick();

           }

 

           interface OnClickListener { // 중첩 인터페이스

                       void onClick();

           }

}

 

UI 클래스

package textbook.chapter9.exam01;

 

public class Window {

          

           Button button1 = new Button();

           Button button2 = new Button();

          

           //필드 선언과 초기값 대입

           //필드로 선언한 익명 구현 객체가 담당하고

           Button.OnClickListener listener = new Button.OnClickListener() {

                      

                       @Override

                       public void onClick() {

                                  System.out.println("전화를 겁니다.");

                       }

           };

          

           //setOnClickListener()를 호출할 때 매개갑으로 준 익명 구현 객체가 담당하도록 했다.

           Window(){

                       button1.setOnClickListener(listener); //매개값으로 필드 대입

                       button2.setOnClickListener(new Button.OnClickListener() {

                                  //매개값으로 익명 구현 객체 대입

                                  @Override

                                  public void onClick() {

                                              System.out.println("메시지를 보냅니다.");

                                  }

                       });

           }

}

 

실행 클래스

package textbook.chapter9.exam01;

 

public class Main {

           public static void main(String[] args) {

                       Window w = new Window();

                       w.button1.touch();

                       w.button2.touch();

           }

}

 

9.5.3 익명 객체의 로컬 변수 사용

익명 객체 내부에서는 바깥 클래스의 필드나 메소드는 제한 없이 사용할 수 있다.

 

문제는 메소드의 매개 변수나 로컬 변수를 익명 객체에서 사용할 때이다.

 

메소드 내에서 생성된 익명 객체는 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용할 수 있다.

 

우리는 익명 클래스의 내부 복사 위치에 신경 쓸 필요 없이 익명 객체에서 사용된 매개 변수와 로컬변수는 모두 final 특성을 갖는다는 것만 알면 된다.

 

다음 예제는 매개 변수와 로컬 변수가 익명 객체에서 사용할 때 final 특성을 갖고 있음을 잘 보여준다.

 

자바 7에서는 반드시 final 키워드를 붙여야 되지만, 자바 8부터는 붙이지 않아도 final 특성을 가지고 있음을 주목해야 한다.

 

void outMethod(final int arg1, int arg2){

final int var1 =1;

int var2 = 2;

class LocalClass{

  void method(){

 int result = arg1+arg2+var1+var2;

}

}

}

 

 

 

인터페이스

package textbook.chapter9.exam02;

 

public interface Calculatable {

           public int sum();

}

 

익명 객체의 로컬 변수 사용

package textbook.chapter9.exam02;

 

public class Anonymous {

           private int field;

          

           public void method(final int arg1, int arg2) {

                       final int var1 =0;

                       int var2 = 0;

                      

                       field = 10;

                      

                       //arg1 = 20;//(x)

                       //arg2 = 20;//(x)

                      

                       //var1 = 30;//(x)

                       //var2 = 30;//(x)

                      

                       Calculatable calc= new Calculatable() {

 

                                  @Override

                                  public int sum() {

                                              int result = field + arg1+arg2+var1+var2;

                                              return result;

                                  }

                                 

                       };

                      

                       System.out.println(calc.sum());

           }

}

 

실행 구현

package textbook.chapter9.exam02;

 

public class AnonymousExample {

           public static void main(String[] args) {

                       Anonymous anony = new Anonymous();

                       anony.method(0, 0);

           }

}

 

확인문제

1. 중첩 멤버 클래스에 대한 설명으로 틀린 것은 무엇입니까? (4)

 

1. 인스턴스 멤버 클래스는 바깥 클래스의 객체가 있어야 사용될 수 있다.

2. 정적 멤버 클래스는 바깥 클래스의 객체가 없어도 사용될 수 있다.

3. 인스턴스 멤버 클래스 내부에는 바깥 클래스의 모든 필드와 메소드를 사용할 수 있다.

4. 정적 멤버 클래스 내부에는 바깥 클래스의 인스턴스 필드를 사용할 수 있다.

 

2. 로컬 클래스에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 로컬 클래스는 메소드 내부에 선언된 클래스를 말한다.

2. 로컬 클래스는 바깥 클래스의 모든 필드와 메소드를 사용할 수 있다.

3. 로컬 클래스는 static 키워드를 이용해서 정적 클래스로 만들 수 있다.

4. final 특성을 가진 매개 변수나 로컬 변수만 로컬 클래스 내부에서 사용할 수 있다.

 

3. 익명 객체에 대한 설명으로 틀린 것은 무엇입니까? (3)

 

1. 익명 객체는 클래스를 상속하거나 인터페이스를 구현해야만 생성될 수 있다.

2. 익명 객체는 필드, 매개 변수, 로컬 변수의 초기값으로 주로 사용된다.

3. 익명 객체에는 생성자를 선언할 수 있다.

4. 부모 클래스나 인터페이스에 선언된 필드와 메소드 이외에 다른 필드와 메소드를 선언할 수 있지만, 익명 객체 내부에서만 사용이 가능하다.

 

4. 다음과 같이 Car 클래스 내부에 Tire Engine이 멤버 클래스로 선언되어 있습니다. NestedClassExample에서 멤버 클래스의 객체를 생성하는 코드를 작성해보세요.

package textbook.chapter9.excersize;

 

public class Car {

            class Tire { }

            static class Engine { }

}

 

package textbook.chapter9.excersize;

 

public class NestedClassExample {

           Car myCar = new Car();

          

           Car.Tire tire = myCar.new Tire();

           Car.Engine engine = new Car.Engine();

}

 

5. AnonymousExample 클래스의 실행 결과를 보고 Vehicle 인터페이스의 익명 구현 객체를 이용해서 필드, 로컬 변수의 초기값과 메소드의 매개값을 대입해보세요.

인터페이스

package textbook.chapter9.excersize;

 

public interface Vehicle {

           public void run();

}

 

익명 구현 클래스와 객체 생성

package textbook.chapter9.excersize;

 

public class Anonymous {

           Vehicle field = new Vehicle() {

                      

                       @Override

                       public void run() {

                                  System.out.println("자전거가 달립니다.");

                       }

           };

          

           void method1() {

                       Vehicle localVar = new Vehicle() {

                                 

                                  @Override

                                  public void run() {

                                              System.out.println("승용차가 달립니다.");

                                  }

                       };

                       localVar.run();

           }

          

           void method2(Vehicle v) {

                       v.run();

           }

}

 

익명 구현 클래스와 객체 생성

package textbook.chapter9.excersize;

 

public class AnonymousExample {

           public static void main(String[] args) {

                       Anonymous anony = new Anonymous();

                       anony.field.run();

                       anony.method1();

                       anony.method2(

                                              new Vehicle() {

                                                        

                                                         @Override

                                                         public void run() {

                                                                    System.out.println("트럭이 달립니다.");

                                                                    

                                                         }

                                              }

                       );

           }

}

 

6. 다음 Chatting 클래스는 컴파일 에러가 발생합니다. 원인이 무엇입니까?

package textbook.chapter9.excersize;

 

public class Chatting {

           void startChat(String chatId) {

                       String nickName = null;

                       nickName = chatId;

                       Chat chat = new Chat() {

                                  @Override

                                  void start() {

                                              while (true) {

                                                         String inputData = "안녕하세요";

                                                         //String message = "[" + nickName + "]" + inputData;

                                                         //sendMessage(message);

                                              }

                                  }

                       };

                       chat.start();

           }

 

           class Chat {

                       void start() {

                       }

 

                       void sendMessage(String message) {

                       }

           }

}

 

5라인과 6라인의 String nickName = null; nickName = chatId;

 

String nickName = chatId; 로 바꾸어준다.

 

 

반응형

' > 이것이 자바다' 카테고리의 다른 글

11. 기본 API 클래스  (0) 2020.10.02
10. 예외처리  (0) 2020.10.01
08. 인터페이스  (0) 2020.09.30
07. 상속  (0) 2020.09.29
06. 클래스  (0) 2020.09.28

+ Recent posts