728x90
반응형

이 글은 MVP 패턴과 DataBinding 라이브러리를 모르면 이해하기 힘든 글입니다.


Android에서 DataBinding은 ButterKnife, KotlinExtension과 같이 편리하고 유용하게 사용할 수 있는 Library 입니다.


저는 MVP+DataBinding 구조로 개인프로젝트를 진행하고 있습니다.

(실제로 이 방식은 deprecated 된 방식입니다.)


이렇게 MVP와 DataBinding을 사용하게 되면 View에 Click Listener를 등록한 다음 Presenter의 함수를 호출하지 않고 바로 xml에서 Presenter의 함수를 호출하는 효과를 볼 수 있습니다.

(내부적으로는 앞에 이야기 한 방식으로 하고 있습니다.)


하지만 layout에 EditText가 있고 값을 가져와서 저장해야 할 때 저는 Presenter가 아닌 View의 함수를 호출해서 사용했습니다.(ㅠㅠ)


그래서 억지로 억지로 사용하다가 오늘 Two Way Binding에 대해 알게 되었습니다.


그럼 이제 예를 통해 오늘의 주제인 DataBinding Two Way Binding에 대해 알아보겠습니다.


  


이번 글에서 예제로 사용할 화면입니다.


왼쪽 화면처럼 이름, 이메일, 폰번호를 입력하고 저장 버튼을 누르면 오른쪽 화면처럼 요약을 보여주려고 합니다.


먼저 Two Way Binding을 모른다고 가정하고 진행해보겠습니다.



<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>

<variable
name="view"
type="com.googry.googrydatabindingtwowaybinding.ui.unknown.UnknownContract.View"/>

<variable
name="user"
type="com.googry.googrydatabindingtwowaybinding.data.User"/>

</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/name"
android:text="@{user.name}"/>

<EditText
android:id="@+id/et_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
android:text="@{user.email}"/>

<EditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/phone"
android:text="@{user.phone}"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> view.onSaveClick()}"
android:text="@string/save"/>

</LinearLayout>
</layout>


layout 입니다.


User를 받아와서 각 EditText에 값을 넣어줍니다.

UnknownContract.View를 받아와서 onClick 이벤트를 받아줍니다.


public interface UnknownContract {
interface Presenter extends BasePresenter {
void save(String name, String email, String phone);
}

interface View extends BaseView<Presenter> {
void setUser(User user);

void showSaveResult(User user);

void onSaveClick();
}

}

UnknownContract 입니다.


Presenter는 name, email, phone을 입력받는 save()를 선언합니다.


View는 setUser(), showSaveResult()와 버튼 클릭 이벤트를 받는 onSaveClick()을 선언합니다.


@Override
public void onSaveClick() {
mPresenter.save(
mBinding.etName.getText().toString(),
mBinding.etEmail.getText().toString(),
mBinding.etPhone.getText().toString()
);
}

UnknownFragment안에 onSaveClick()를 구현했습니다.

이 부분에서 EditText의 내용을 가져와 Presenter에 save()함수를 통해 전달해 줍니다.


@Override
public void save(String name, String email, String phone) {
mUser.name = name;
mUser.email = email;
mUser.phone = phone;

mUserDataSource.saveUser(mUser);
mView.showSaveResult(mUser);
}

UnknownPresenter안에 save()를 구현했습니다.


내부적으로 mUser에 값을 넣어주고 UserDataSource에 User를 저장하고 View에 결과를 보여주라고 showSaveResult()함수를 호출 합니다.


@Override
public void showSaveResult(User user) {
new AlertDialog.Builder(getContext())
.setMessage(user.toString())
.show();
}

그리고 UnknownFragment에서 AlertDialog를 통해 결과를 보여주게 됩니다.


이렇게 순서가 xml -> View.onSaveClick() -> Presenter.save() -> View.showSaveResult() 입니다.


하지만 버튼 클릭을 했을 때 각 EditText내용의 값을 가져오면서 View의 함수를 호출하는 것이 아닌 바로 Presenter의 함수를 호출 할 수 있을까요?

다르게 말하자면 View.onSaveClick()을 호출하지 않고 xml -> Presetner.save() -> View.showSaveResult()를 할 수 있을까요?


네, 바로 Two Way Binding을 하게 되면 할 수 있습니다.


그럼 이제 Two Way Binding을 하는 방법에 대해 알아보겠습니다.


private User mUser;

@Override
public void start() {
mView.setUser(mUser);
}

Presenter안에 User가 있고 View에 User객체를 전달해줍니다.


그리고 Contract.View에 있는 setUser()라는 함수의 구현부분은 이렇게 생겼습니다.

@Override
public void setUser(User user) {
mBinding.setUser(user);
}

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>

<variable
name="presenter"
type="com.googry.googrydatabindingtwowaybinding.ui.known.KnownContract.Presenter"/>

<variable
name="user"
type="com.googry.googrydatabindingtwowaybinding.data.User"/>

</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/name"
android:text="@={user.name}"/>

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
android:text="@={user.email}"/>

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/phone"
android:text="@={user.phone}"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{() -> presenter.save()}"
android:text="@string/save"/>

</LinearLayout>
</layout>

저렇게 binding에 넣어준 User를 @{}가 아닌 @={}로 각 EditText에 binding 하면 됩니다.


이렇게 했을 경우 EditText에서 text가 변경 될 때 마다 User안에 값을 변경하게 됩니다.


User객체는 Presenter에서 관리하고 있기 때문에 그럼 각 EditText에서 값을 가져와 Presenter에 전달해줄 필요가 없게 됩니다.


그래서 바로 버튼에 onClick에서 presenter.save()를 호출 할 수 있게 되는 것입니다.




이렇게 Two Way Binding을 사용하게 되면 바로 Presenter의 함수를 호출하여 함수 호출의 depth가 낮아지게 되는 효과를 볼 수 있습니다.


예제 코드는 https://github.com/sjjeong/GoogryDataBindingTwoWay 에서 확인하실 수 있습니다.

728x90
반응형
728x90
반응형

이번 포스팅에서는 Mysql에서 Sql문을 사용해서 데이터를 CRUD하는 방법에 대해 알아보려고 합니다.


일단 CRUD는 Create(생성), Read(읽기), Update(갱신), Delete(삭제)의 앞글자만 따서 CRUD라고 부릅니다.


먼저 읽기에 대해 알아보겠습니다.


여기서 사용할 샘플 데이터는 http://futurists.tistory.com/19를 참고했습니다.


sql에서 읽기는 SELECT명령어를 사용합니다.

문법은 SELECT 열명 FROM 테이블명; 입니다.

열명에 *를 넣게 되면 테이블에서 전체 열을 가져올 수 있고 ,를 사용하게 되면 복수의 열을 가져 올 수 있습니다.


하지만 이렇게 사용하면 테이블에 있는 모든 데이터를 가져오게 되는데 특정 조건에 해당하는 데이터만 가져오기 위해서 WHERE을 추가해 줘야합니다.

문법은 SELECT 열명 FROM 테이블명 WHERE 조건; 입니다.

여기서 조건에 들어가는 비교연산자는 다음과 같습니다.

= 같다

<> 같지않다

>= 크거나 같다

> 크다

<= 작거나 같다

< 작다


SELECT * FROM employees WHERE gender = 'M';

이렇게 명령어를 작성하면 employees 테이블에서 gender가 M인 데이터를 전부 가져오는 것입니다.

특정 조건에 해당하는 데이터만 가져올 수 있게 됩니다.



SELECT * FROM employees WHERE gender = 'M' AND hire_date > '1999-01-01';

이렇게 명령어를 작성하면 employees 테이블에서 gender가 M이며 hire_date가 1991-01-01이상인 데이터만 가져오게 됩니다.

조건에 AND나 OR를 사용하면 여러개의 조건을 붙일 수 있습니다.



데이터를 읽어오면서 정렬을 하기 위해선 ORDER BY 명령어를 추가해주면 됩니다.

SELECT * FROM employees WHERE gender = 'M' AND hire_date > '1999-01-01' ORDER BY hire_date DESC;

데이터를 가져오면서 hire_date를 내림차순으로 가져오게 됩니다.

그럼 가장 처음데이터가 최신이고 마지막데이터는 마지막이 되는 것입니다.



다음은 테이블을 요약하는 함수입니다.

count, sum, avg는 복수개의 값들의 개수, 합, 평균을 계산하는 함수이고

max, min은 복수개의 값중에 최대값과 최소값을 구하는 함수입니다.


SELECT avg(salary) FROM salaries;

salaries테이블의 salary의 평균을 구하는 명령어 입니다.



SELECT max(salary) FROM salaries;

salaries테이블의 salary의 최대값을 구하는 명령어 입니다.



데이터를 그룹화 해서 가져오기 위해서 GROUP BY 명령어를 사용합니다.

SELECT dept_no, count(*) FROM dept_manager GROUP BY dept_no;

dept_no와 count(*)를 dept_manager에서 가져오고 dept_no로 그룹화해서 보여주는 것입니다.


그리고 GROUP BY에서 조건을 걸고 싶다면 HAVING 명령어를 사용합니다.

SELECT dept_no, count(*) FROM dept_manager GROUP BY dept_no HAVING count(*) = 4;


그리고 SELECT 명령어를 사용 할 때 1. SELECT 2. FROM 3. WHERE 4. GROUP BY 5. HAVING 6. ORDER BY 순서대로 써야합니다.



이제 생성(CREATE)를 하는 INSERT 명령어에 대해 알아보겠습니다.

INSERT의 기본 구조는 INSERT INTO 테이블명 VALUES 데이터; 입니다.

우선 DESC dempartments;로 테이블의 형태를 보겠습니다.

dept_no는 char(4)타입이며 primary key입니다.

dept_name은 varchar(40)타입입니다.


SELECT * FROM departments ORDER BY dept_no;로 값들을 확인합니다.


그럼 이제 dept_no가 d010이고 dept_name이 Mobile App인 값을 넣어보겠습니다.

INSERT INTO departments VALUES ('d010', 'Mobile App');

데이터 생성에 성공했습니다.

SELECT * FROM departments ORDER BY dept_no;로 확인해보면

d010에 Mobile App이 추가된 것을 확인 할 수 있습니다.


한번에 복수개를 넣고 싶다면 INSERT INTO departments VALUES (), (), (), ... (); 로 작성하면 됩니다.


이제 데이터를 변경하는 UPDATE에 대해 알아보겠습니다.

UPDATE의 기본 구조는 UPDATE 테이블명 SET 열명 = 값; 입니다.

UPDATE에도 WHERE을 사용해 특정 조건에 해당하는 값만 갱신 할 수 있습니다.


그럼 우리는 d010의 dept_name을 Mobile App에서 Mobile Development로 변경하겠습니다.

UPDATE departments SET dept_name = 'Mobile Deveopment' WHERE dept_no = 'd010';

데이터 변경에 성공했습니다.


SELECT * FROM departments ORDER BY dept_no;로 확인해보겠습니다.


d010의 dept_name이 Mobile App에서 Mobile Development로 변경된 것을 확인 할 수 있습니다.


이제 데이터를 지워보겠습니다.

제거 명령어는 DELETE이고 기본구조는 DELETE FROM 테이블명; 입니다.

저렇게하면 테이블의 모든 데이터가 다 지워지게 됩니다.

그래서 WHERE를 추가해 원하는 조건의 데이터만 지우게 해야 합니다.

그럼 아까 추가한 d010의 데이터를 지워보겠습니다.


DELETE FROM departments WHERE dept_no = 'd010';

데이터 삭제에 성공했습니다.


SELECT * FROM departments ORDER BY dept_no;로 확인해보겠습니다.


데이터가 지워진 것을 확인 할 수 있습니다.



이 다음은 결합에 대해 알아보겠습니다.

결합은 두개이상의 테이블에서 값을 동시에 가져올 때 사용합니다.

그리고 결합에는 내부결합과 외부결합 2가지가 있습니다.


내부결합은 INNER JOIN 테이블명 ON 조건으로 가져옵니다.

예제는 dept_manager 테이블에 departments테이블의 dept_name을 붙여서 가져오는 것을 해보겠습니다.


SELECT dept_manager.*, departments.dept_name FROM dept_manager INNER JOIN departments ON dept_manager.dept_no = departments.dept_no;


INNER JOIN은 FROM에 있는 테이블에 있고 ON뒤에 조건에 만족하는 값들만 가져오게 됩니다.


OUTTER JOIN을 쓰게 되면 FROM에 있는 테이블은 모두 가져오고 OUTER JOIN에 있는 테이블의 값만 추출해서 넣게 됩니다.

기본 형태는 SELECT 열명 FROM 왼쪽테이블 LEFT OUTTER JOIN 오른쪽테이블 ON 조건; 입니다.

이렇게 하면 왼쪽 테이블에 있고 오른쪽 테이블에 없는 것들은 NULL로 들어가게 됩니다.


728x90
반응형

'Development > Database' 카테고리의 다른 글

(DB) 테이블 설계의 기초와 정규형  (3) 2017.09.27
(DB) Mac OS에서 MySQL 설치하기  (0) 2017.09.22
(DB) 관계형 데이터베이스란?  (0) 2017.09.21
(DB) 데이터베이스란?  (0) 2017.09.21
728x90
반응형

저번 포스팅에서 다뤘던 스위프트의 속성을 사용해서 다양한 연산자(Operator)를 처리하는 방법에 대해 설명하고자 합니다.


연산자를 사용하면 값을 합치고, 변경하고, 검사 할 수 있습니다.

예를 들면 1 + 2처럼 +라는 연산자를 사용할 수 있고 &&를 사용해 Bool 값을 연산할 수 있습니다.


연산자는 단항, 이항, 삼항으로 분류 할 수 있습니다.


단항은 single target(-a), prefix operator(!b), postfix operator(c!)와 같은 것이 있습니다.

이항은 two targets(2 + 3)와 같은 것이 있습니다.

삼항은 three targets(a ? b : c)와 같은 것이 있습니다.


연산자에 영향을 주는 Value를 operand라고 부릅니다.

1 + 2에서 +는 binary operator이며 1과 2는 operand라고 말할 수 있습니다.



Assignment Operator

할당 연산자는 값을 초기화하거나 갱신하는 역할을 합니다.


let b = 10

var a = 5

a = b

// a is now equal to 10



Arithmetic Operators

스위프트는 4개의 Arithmetic Operator를 제공합니다.

- Addition +

- Subtraction -

- Multiplication *

- Division /


1 + 2       // equals 3

5 - 3       // equals 2

2 * 3       // equals 6

10.0 / 2.5  // equals 4.0


그리고 Addition Operator는 String를 합칠때 사용 할 수 있습니다.


var helloworld = "hello, " + "world"  // equals "hello, world"



Remainder Operator

나머지 연산자는 %를 사용하고 left value를 right value로 나누고 남은 나머지를 반환합니다.


9 % 4       // equals 1



Compound Assignment Operator

합성 할당 연산자는 Assignment와 이항연산자를 합친 연산자입니다.


var a = 1

a += 2

// a is now equal to 3


a += 2는 실제로 a = a + 2로 볼 수 있습니다.



Comparison Operators

비교 연산자는 6개가 있습니다.

- Equal to ==

- Not equal to !=

- Greater than >

- Less than <

- Greater than or equal to >=

- Less than or equal to <=


1 == 1   // true because 1 is equal to 1

2 != 1   // true because 2 is not equal to 1

2 > 1    // true because 2 is greater than 1

1 < 2    // true because 1 is less than 2

1 >= 1   // true because 1 is greater than or equal to 1

2 <= 1   // false because 2 is not less than or equal to 1



Ternary Conditional Operator

삼항 연산자는 if..else와 비슷합니다.

form은 question ? answer1 : answer2 의 형태입니다.

question이 true이면 answer1을, false이면 answer2를 반환합니다.


let contentHeight = 40

let hasHeader = true

let rowHeight = contentHeight + (hasHeader ? 50 : 20)

// rowHeight is equal to 90



Nil-Coalescing Operator

nil 결합 연산자는 Optional value가 값을 가지고 있는지 확인해서 값을 리턴하는 연산자 입니다.


a ?? b

a가 nil이 아니면 a를, nil이면 b를 반환합니다.

이 코드는 아래와 같이 나타낼 수 있습니다.


a != nil ? a! : b



Range Operators

범위 연산자는 3가지 종류가 있습니다.

- Closed Range Operator a...b

- Half-Open Range Operator a..<b

- One-Sided Ranges Operator a... / ...b



Logical Operators

논리 연산자는 operand가 Boolean인 것들의 Operator입니다.

- Logical Not !a

- Logical And a && b

- Logical OR a || b



728x90
반응형

'Language > Swift' 카테고리의 다른 글

(Swift) 스위프트 속성(Property)기초  (0) 2017.10.08
(Swift) 스위프트 맛보기  (0) 2017.10.07
728x90
반응형

스위프트는 정수형 타입인 Int와 실수형 타입인 Double, Float와 참과 거짓을 나타내는 Bool과 문자열을 나타내는 String의 데이터 타입이 있고 Collection 타입인 Array, Set, Dictionary도 제공합니다. 또한 Objective-C에서 제공하던 Tuple도 제공합니다. 그리고 새로 추가된 Optional을 제공합니다. Optional타입은 nil값을 저장 할 수 있습니다.


스위프트에서 데이터는 상수 또는 변수로 나타낼 수 있습니다. 상수는 let 키워드를 사용하고 변수는 var 키워드를 사용합니다.


let maximumNumberOfLoginAttempts = 10

var currentLoginAttempt = 0


이 코드는 아래와 같이 해석 할 수 있습니다.

maximumNumberOfLoginAttempts 상수를 선언 했고 10으로 초기화 했다.

currentLoginAttempt 변수를 선언 했고 0으로 초기화 했다.


그리고 한 줄에 여러개의 변수를 선언함과 동시에 초기화도 같이 할 수 있습니다.


var x = 0.0, y = 0.0, z = 0.0


만약에 우리가 변수를 선언하고 값을 초기화 하지 않으면 어떤 일이 발생할까요?


var x

이렇게 type annotation이 빠졌다고 에러를 보여주게 됩니다.


그럼 Type Annotation이란 무엇일까요?

Type Annotation은 변수나 상수의 이름 뒤에 "이것이 어떤 타입이다"라고 명시적으로 알려주는 것입니다.


var welcomeMessage: String

바로 이렇게 말이죠.


여기서 :은 of type라는 의미를 가지고 있습니다. welcomeMessage는 String type의 var라는 거죠.


Integer(정수)는 소수점이 없는 숫자를 나타낼 수 있습니다.

기본적으로 Int는 32비트 플랫폼에서는 Int32처럼 동작하고 64비트 플랫폼에서는 Int64처럼 동작합니다.

UInt는 unsigned int로 0이상의 자연수를 나타낼 수 있습니다. 다른말로 음수값은 가질 수 없는 거죠.

UInt도 Int와 마찬가지로 32비트, 64비트 플랫폼에 따라 UInt32, UInt64로 동작합니다.


실수는 Double과 Float로 나타낼 수 있습니다.

Double은 64비트 범위를 나타낼 수 있고 Float는 32비트 범위를 나타낼 수 있습니다.



정수는 Literal을 이용하면 2진수, 8진수, 16진수로 나타낼 수 있습니다.


let decimalInteger = 17

let binaryInteger = 0b10001       // 17 in binary notation

let octalInteger = 0o21           // 17 in octal notation

let hexadecimalInteger = 0x11     // 17 in hexadecimal notation


실수도 Literal을 이용해서 만들 수 있습니다.


let literalDecimal1 = 1.25e2    // 125

let literalDecimal2 = 1.25e-2   // 0.0125

let literalDecimal3 = 0xfp0     // 15

let literalDecimal4 = 0xfp2     // 60

let literalDecimal5 = 0xfp-2    // 3.75


e는 10^이고 p는 2^ 입니다.

1번은 1.25 * 10^2

2번은 1.25 * 10^-2

3번은 15 * 2^0

4번은 15 * 2^2

5번은 15 * 2^-2


튜플은 여러개의 값을 그룹화 시킬 수 있습니다.

예를 들어서 HTTP status code인 404는 "Not Found" 입니다.

이것은 (404, "Not Found")라고 튜플형태로 만들 수 있습니다.


let http404Error = (404, "Not Found")


이것을 사용하기 위해서는

1.

let (statusCode, statusMessage) = http404Error

print("The status code is \(statusCode)")

// Prints "The status code is 404"

print("The status message is \(statusMessage)")

// Prints "The status message is Not Found


2.

let (justTheStatusCode, _) = http404Error

print("The status code is \(justTheStatusCode)")

// Prints "The status code is 404


3. 

print("The status code is \(http404Error.0)")

// Prints "The status code is 404"

print("The status message is \(http404Error.1)")

// Prints "The status message is Not Found


4.

let http200Status = (statusCode: 200, description: "OK")

print("The status code is \(http200Status.statusCode)")

// Prints "The status code is 200"

print("The status message is \(http200Status.description)")

// Prints "The status message is OK


이런식으로 사용 할 수 있습니다.


튜플을 사용하게 되면 함수에서 여러개의 값을 한번에 리턴 시킬 수 있습니다.


Optional은 C나 Objective-C에서는 없던 개념입니다.

이것은 값의 부재를 나타냅니다. 다른 말로 값이 있던지, 값이 없던지 입니다.

값이 있는 것은 정수형에서는 0이나 19로 나타내는 것이고 값이 없다는 것은 nil로 값을 설정해주는 것입니다.


var serverResponseCode: Int? = 404

// serverResponseCode contains an actual Int value of 404

serverResponseCode = nil

// serverResponseCode now contains no value


Optional은 타입뒤에 ?를 붙여줍니다.

serverResponseCode는 Optional Int타입이며 404 값으로 초기화 되었습니다.

그 다음에 nil로 값을 비워줬습니다.


nil은 Optional 타입이 아닌 변수에 설정 할 수 없습니다.

Optional 타입의 변수에 값을 초기화 해주지 않으면 스위프트는 자동으로 nil값으로 초기화 해줍니다.


728x90
반응형

'Language > Swift' 카테고리의 다른 글

(Swift) 스위프트 연산자(Operator) 기초  (0) 2017.10.09
(Swift) 스위프트 맛보기  (0) 2017.10.07
728x90
반응형

예전에 Objective-C언어를 사용해서 iOS, MacOS위에서 동작하는 앱을 개발했습니다.


그리고 2014년 6월 2일 WWDC를 통해 스위프트가 소개되었고 그 이후로 스위프트를 통해 많은 앱들이 개발 되었습니다.


스위프트를 사용해 개발하기 위해서는 MacOS기반 개발환경이 필요하고 XCode가 설치되어있어야 합니다.


그리고 playground에서 스위프트를 사용해서 코드를 작성하면 결과를 즉시 확인 할 수 있습니다.



이렇게 말이죠.


앞으로의 포스팅에서는 스위프트언어에 대해서 알아보고 아이폰 개발에 대해 알아보겠습니다.


제가 참고하는 자료는 The Swift Programming Language (Swift 4) 입니다.


728x90
반응형

'Language > Swift' 카테고리의 다른 글

(Swift) 스위프트 연산자(Operator) 기초  (0) 2017.10.09
(Swift) 스위프트 속성(Property)기초  (0) 2017.10.08
728x90
반응형

이전 글에서 흐름제어에 대해 알아보았습니다.


이번에는 흐름제어에서 반복문을 좀 더 유연하게 사용할 수 있게 하는 break와 continue에 대해 알아보겠습니다.


먼저 간단하게 개념에 대해 이야기하겠습니다.

break는 멈춘다는 의미로 가장 가까이에 있는 반복문을 멈추고 밖으로 나가는 명령어입니다.

continue는 계속한다는 의미로 반복문의 한 사이클을 중간에 멈추고 다음 사이클을 실행하라는 명령어입니다.


간단한 예로 시작 하겠습니다.

for (i in 1..3) {
for (j in 1..3) {
println("${i} * ${j} = ${i * j}")
}
}


i가 1부터 3까지 반복하면서

j가 1부터 3까지 반복하면서

${i} * ${j} = ${i * j}를 출력하는 코드입니다.


그러면 중간에 변화를 주겠습니다.


for (i in 1..3) {
for (j in 1..3) {
if (i * j == 6) {
break
}
println("${i} * ${j} = ${i * j}")
}
}


2 * 3 = 6

3 * 2 = 6

3 * 3 = 9

이렇게 3개의 결과가 출력되지 않는 것을 확인 할 수 있습니다.


그 이유는 i * j가 6이 되는 시점에 j가 속해있는 for문을 break로 인해 멈추기 밖으로 나가기 때문입니다.


for (i in 1..3) {
for (j in 1..3) {
if (i * j == 6) {
continue
}
println("${i} * ${j} = ${i * j}")
}
}


이번에는 break와는 다르게

3 * 3 = 9

가 출력이 되었습니다.


그 이유는 continue는 반복문 자체를 멈추는 것이 아니라 현재 반복문의 한 사이클을 멈추고 다음 사이클을 실행하기 때문입니다.

그래서 i * j의 값이 6이 되는 부분만 출력하지 않고 나머지 반복문을 계속 진행하는 것입니다.




다음은 java에는 없고 c를 배울 때 사용 했던 goto문과 비슷한 것에 대해 알아보겠습니다.

바로 break와 continue에 label를 붙이는 것입니다.


loop1@ for (i in 1..3) {
loop2@ for (j in 1..3) {
if (i * j == 6) {
continue@loop1
}
println("${i} * ${j} = ${i * j}")
}
}


for앞에 loop1@라는 라벨이 생겼습니다.

continue뒤에 @loop1라는 라벨이 생겼습니다.


결과값은 break문과 동일합니다.

그 이유는 i가 속해있는 for문에 loop1라는 라벨을 넣어주고 continue에서 loop1 라벨을 붙여주었고 그로 인해 loop1으로 점프한 효과를 볼 수 있기 때문입니다.


loop1@ for (i in 1..3) {
loop2@ for (j in 1..3) {
if (i * j == 6) {
break@loop1
}
println("${i} * ${j} = ${i * j}")
}
}


이제는 continue대신 break에 라벨을 붙여봤습니다.


이제는 i * j가 6일 때 loop1라벨이 붙은 반복문을 break해버립니다.

그래서 결과가 2 * 3 = 6일 때 i가 속해있는 반복문이 멈추게 됩니다.


이렇게 라벨을 사용하게 되면 이중포문 혹은 삼중포문에서 탈출을 한번에 할 수 있는 효과를 볼 수 있습니다.

728x90
반응형

+ Recent posts