1. 람다식 (Java Lambda Expression)

함수를 변수처럼 사용하는 것.

파라미터로 함수를 다른 메소드의 인자로 전달할 수 있고, 리턴 값으로 함수를 받을 수도 있다.

객체지향 언어인 자바에 함수형 프로그래밍의 개념을 대입하기 위한 인터페이스.

 

자바 람다식은 함수형에 대해 새로 정의한게 아닌, 기존에 존재하는 인터페이스의 형태를 받아 람다식을 표현하기 때문에 함수형 프로그래밍의 장점을 완전히 가지지는 못하고 있다.

 

순번 

장점 

단점 

 1

 코드가 간결해짐

 람다식 호출을 위해 직접 메소드를 불러야 함

 - 타 함수의 파라미터로 전달할 때에는 문제가 없으나, 람다식을 실행할 때에는 인터페이스에 선언된 메소드를 호출해야 함

 2

 병렬 프로그래밍이 가능해짐

 - 반복 대상을 사용자 코드에서 직접 지정하기 않기 때문에 Collection API가 크게 효과적으로 개선됨

 재귀 람다식의 호출이 까다로움

 - 람다식 안에서는 람다식을 가리키는 변수를 참조할 수 없기 때문에 람다식 안에서 자신을 다시 호출하기가 까다로움.

 (배열 등의 트릭을 사용하여 가능하게 할 수는 있음)

 3

 메소드로 행동 방식을 전달 가능

 - 행동 방식 그 자체를 람다식으로 구현하여 전달함

 클로저가 지원되지 않음

 - 자바에서는 외부 변수에 대해 사실상 final 형태로서만 참조가 가능

 (일반적 함수형 프로그램에서는 클로져 형태로 외부 변수의 라이프 사이클 연장 가능)

 4

 의도의 명확성

 - 코드에서 드러내고자 하는 개발자의 의도를 함축적이면서도 추상화시켜 나타낼 수 있음

 함수 외부의 값을 변경함

 - 자바는 기본적으로 객체 모델로서, 함수 안의 값이 타 객체의 영향을 받는 경우 같은 입력 값에 대해 다른 출력 값을 출력할 수 있어 병렬형 프로그래밍에 불리한 방식을 보임

 

<예제1>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class RamdaMain {
    public static void main(String[] args) {
        
//      기존 익명 클래스 방식
        new Thread(new Runnable() {
            public void run() {
                System.out.println("Annoymous Thread");
            }
        }).start();
        
//      람다 표현식 방식
//      () : 파라미터. run()이라는 익명 클래스의 메소드가 아무런 파라미터도 취하지 않는다는 의미
//      -> : 람다식 시작 전에 나타나는 람다식 시작 토큰
//           뒤에는 한 줄짜리 람다식, 혹은 { } 안에 포함된 여러 람다식이 올 수 있음
//      System.~ : 람다식의 내용 부분. 안에는 () 안의 파라미터 값이 사용될 수 있음
        new Thread(()->System.out.println("Lambda Thread")).start();
    }
}
cs

 

<예제2>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//@FunctionalInterface : 인터페이스 형태를 이용하여 람다 클래스임을 선언할 수 있기 때문에
//                         해당 주석을 달아 람다 인터페이스임을 선언함.
// 람다식은 그 자체를 입력 값으로 사용할 수 있지만,
// 받아서 실제로 런타임 시 사용할 때에는 반드시 인터페이스의 형태를 거쳐야 함
@FunctionalInterface
public interface Test {
    public abstract void run();
}
 
public class TestMain {
    public static Test lambdaTest(Test test) {
        test.run();
        return () -> System.out.println("return lambda");
    }
    
    public static void main(String[] args) {
        lambdaTest(() -> System.out.println("input lambda")).run();
    }
}
cs

 

 

2. 함수형 프로그래밍 (<=> 명령형 프로그래밍)

자바는 객체 지향적인 언어이기 때문에(객체지향 : 각각 독립적일 수 있는 것) 그간 익명 함수(일회성 함수)를 사용하지 못했었는데,

Java8 이상부터 람다 표현식이 사용 가능해짐에 따라 함수를 변수처럼 사용할 수 있는 함수형 프로그래밍을 자바에서도 사용 가능할 수 있게 되었다.

 

보통 함수형 프로그래밍의 대표적인 언어라고 하면 자바스크립트를 들 수 있다.

 

함수형 프로그래밍이 도입된 이후로 자바에서도 절차 지향적인 부분을 조금이라도 구현 가능할 수 있게 되었다.

(일회성으로 순서대로 사용하고 말아버리고, 독립된 객체가 아니기 때문에 절차 지향이라고 표현하였음)

 

람다 표현식은 익명 함수를 만들 때 사용하지만, 자바 언어에서는 함수라는 개념이 존재하지 않기 때문에

추상 메소드만 있는 형태의 인터페이스를 만들어 이 인터페이스의 익명 클래스를 만들면서 메소드 오버라이딩에 람다식을 이용하는 인터페이스를 제공한다.

=> 함수형 인터페이스 ( <예제2> 참고)

'BackEnd > Java' 카테고리의 다른 글

초기화 블록 (Initialization block)  (0) 2017.02.13
AWT vs 스윙 (Swing)  (0) 2017.02.10
자바 기본 정리  (0) 2017.02.09
Java :: startsWith() vs indexOf() vs charAt()  (0) 2016.12.26
Java :: Reflection 리플렉션  (0) 2016.12.18

1. 클래스

객체를 정의해 놓은 것. 객체를 생성하는데 사용한다.

실제로 존재하는 사물인 객체를 프로토타입으로 명세화 시킨 것이 클래스이다.

 

* 구성 요소

ㄱ. 클래스 헤더  : 클래스명

클래스 선언부. class라는 예약어를 중심으로 오른쪽은 클래스명이고, 왼쪽은 접근 제한자와

클래스의 형태, 클래스의 종류를 나타냄.

ㄴ. 멤버 필드 : 변수, 상수 등의 속성

객체가 만들어질 때 해당 객체의 특징적 속성을 담게 됨.

ㄷ. 멤버 메소드 : 동작하는 메소드

메소드는 특정한 기능을 수행하는 행위를 의미함

 

 

2. 객체

실제로 존재하는 사물, 또는 실제로 존재하는 개념 등.

속성과 기능의 집합. 이 두 개를 객체의 멤버라고 부른다.

속성과 기능에 따라 용도는 천차만별로 달라질 수 있고, 정의된 클래스로 객체를 생성할 수 있다.

 

 

3. 인스턴스

객체 > 인스턴스.

클래스로부터 인스턴스를 생성하여 인스턴스화 시킨다고 말할 수 있다.

클래스 -> 인스턴스화 -> 인스턴스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//Human 클래스
public class Human {
//  변수 선언
    String name;
    String gender;
    int age;
    
    public Human() { }
    
    public Human(String name) {
        this.name = name;
    }
    
    public Human(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    
    public void eat(String some) {
        System.out.println("console> age : " + age +
                    ", name : " + name + ", some : " + some + "을 먹는 중.");
    }
    
    public void sleep() {
        System.out.println("console> age : " + age +
                    ", name : " + name + "이가 자는 중.");
    }
}
 
//HumanMain 클래스
public class HumanMain {
    public static void main(String[] args) {
//      Human이라는 클래스 주소를 human이라는 이름의 인스턴스에 주소값을 복사하여 객체화함
        Human human = new Human();
        
        human.name = "사람1";
        human.gender = "여";
        human.age = 100;
        
        human.eat("과자");
        human.sleep();
        
        Human human1 = new Human("사람2""남"99);
        Human human2 = new Human("사람3");
        
        human1.eat("껌");
        human2.eat("커피");
    }
}
cs


1. boolean startsWith(String str)

특정 값이 인자로 받은 해당 접두사와 일치하는 경우 true, 일치하지 않은 경우 false를 리턴하는 메소드 

 

 

* <=> boolean endsWith(String str)

 

2. boolean indexOf()

 

 

3. charAt()

'BackEnd > Java' 카테고리의 다른 글

람다식과 함수형 프로그래밍 (Java 8.0 이상)  (0) 2017.02.09
자바 기본 정리  (0) 2017.02.09
Java :: Reflection 리플렉션  (0) 2016.12.18
Java :: Exception 예외처리  (0) 2016.12.15
Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22

1. 정의

객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법

형은 알고 있지만 형변환을 할 수 없는 상태에서 객체의 메소드를 호출할 수 있음


자바에서는 클래스의 정보를 분석하기 위한 도구로 Class 클래스를 제공해주고 있는데, .class의 등록 정보 클래스, 바이트 코드의 등록 정보 클래스로 표현할 수 있다.


Class 클래스는 java.lang 패키지 소속의 클래스이며 Method, Field, Constructor는 java.lang.reflect 패키지에 존재한다.

그렇기 때문에 자바의 리플렉션 기법을 사용하기 위해서는 무조건 java.lang.reflect 패키지를 import 한 후에 사용해야 한다.



2. 정적 바인딩

컴파일시 이미 컴파일러가 Data 클래스를 알고 있는 상태(class path가 지정된 곳에 클래스 자체가 존재해야 함)

컴파일 시점에 이미 로딩되어 있음 (ex. new 연산자)

다운 캐스팅도 가능하고 마음대로 Data라는 형을 사용할 수 있음


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.example;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class ShowClassInfoMain {
    public static void main(String[] args) {
//      Integer 클래스 데이터 타입을 Class 클래스 데이터 타입 c로 값 복사
//      Integer 클래스는 java.lnag 패키지 소속이기 때문에 자동 import
        Class c = Integer.class;
        
//      클래스, 생성자, 메소드, 필드명 객체 주소 알아내기(여러개일 수 있으므로 배열로 받는다)
        Class[] iface = c.getInterfaces();
        Constructor [] ctor = c.getConstructors();
        Method [] m = c.getMethods();
        Field[] f = c.getFields();
        
//      Integer 클래스 타입인 c를 Class타입인 temp로 값 복사함
        Class temp = c;
        
//      temp와 temp.getSuperClass. 상위 클래스의 값이 null이 아닌 경우 무한 반복
//      (상위 클래스들을 모두 역으로 추적하기 위해 while문 사용함)
//      => 상위 클래스 : Number, Object (콘솔 창에 출력되는 결과)
        while ( (temp = temp.getSuperclass()) != null) {
            System.out.println(temp);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 인터페이스 배열들 출력하는 for문
        for (int i = 0; i < iface.length; i++) {
            System.out.println("interface[" + i + "] = " + iface[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 생성자 배열들 출력하는 for문
        for (int i = 0; i < ctor.length; i++) {
            System.out.println("Constructor[" + i + "] = " + ctor[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 메소드 배열들 출력하는 for문
        for (int i = 0; i < m.length; i++) {
            System.out.println("Methoid[" + i + "] = " + m[i]);
        }
        
        System.out.println();
        
//      Integer 클래스 데이터 타입인 필드 배열들 출력하는 for문
        for (int i = 0; i < f.length; i++) {
            System.out.println("Field[" + i + "] = " + f[i]);
        }
    }
}
cs

<클래스 정보 출력하는 예제>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.example;
 
//정적 바인딩을 이용해 다운 캐스팅 하는 클래스
public class Data {
    public void sayHello() {
        System.out.println("Hello World!");
    }
}
 
package com.example;
 
public class StaticBindingMain {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//      정적 바인딩으로 Data 클래스를 사용함
//      정적 바인딩 : 개발자가 .class 파일을 직접 로딩한 후 Class 클래스를 이용하여 객체를 생성하면
//                    JVM이 그 다음 작업을 해주는 것
//      1단계 > .class : 개발자가 .class 파일을 직접 로딩하여 Class 클래스에 값 복사함
        Class c = Data.class;
//      2단계 > newInstance() : Class 클래스 이용하여 객체를 직접 생성하는 메소드
//                         (정적 바인딩을 직접 하기 위해)
        Object obj = c.newInstance();
        
//      정적 바인딩으로 Data 클래스를 사용함
//      (Data 라는 해당 클래스가 프로젝트 안에 실제로 존재해야 함)
        Data d = (Data) obj;
        Class c2 = d.getClass();
        
//      정적 바인딩으로 Data 클래스를 사용함
        Data d2 = (Data) c2.newInstance();
        
        System.out.println(d);
        System.out.println(d2);
        
        d.sayHello();
        d2.sayHello();
    }
}
cs

<정적 바인딩 예제>



3. 동적 바인딩

일반적으로 말하는 리플렉션의 기법

런타임(실행) 시점에 로딩되기 때문에 컴파일 시에는 해당 클래스가 없어도 됨

프로그램이 실행되고 난 뒤 동적으로 위치를 명시하고, 해당 클래스( .class) 를 로딩하여 객체를 만들고 메소드를 호출함

해당 클래스가 바로 존재하지 않아도 클래스의 위치와 이름만 알면 찾을 수 있음 (ex. Class.forName(String str))


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.example;
 
public class DynamicData {
    public void sayHello() {
        System.out.println("안녕하세요!");
    }
    
    public void goodBye() {
        System.out.println("안녕히계세요!");
    }
}
 
package com.example;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
 
public class DynamicDataClassMain {
    public static void main(String[] args) throws IOException, InstantiationException, 
                                                    IllegalAccessException, ClassNotFoundException {
        System.out.println("다운로드중 ...");
        
//      웹 서버에 존재하는 파일에 연결된 스트림을 생성하는 방법
        URL url = new URL("http://www.jabook.org/DynamicData.class");
        InputStream is = url.openStream();
        
//      스트림을 통해 읽은 데이터를 저장하기 위해 파일 출력 스트림 생성
        FileOutputStream fos = new FileOutputStream("DynamicData.class");
        
        int i;
        
//      입력 & 출력 스트림이 생성되었을 시 반복
        while ( (i = is.read()) != -1) {
            fos.write(i);
            
            System.out.println("|");
        }
        
//      열어놨던 입출력 스트림들은 반드시 닫아줘야 함
        fos.close();
        is.close();
        
        System.out.println("\n 다운로드 완료 ...");
        
//      클래스의 이름 자체를 컴파일 타임에 사용할 수 없기 떄문에 문자열 형태로 클래스의 이름을 사용
//      Class.forName(String str)이 호출되는 그 순간 클래스를 로딩하겠다는 의미
//      매개변수가 String 형인 이유 : 해당 클래스가 컴파일시 없기 때문
        Class c = Class.forName("DynamicData");
        
//      동적으로 생성된 Class 정보를 이용해서 객체 생성
        Object obj = c.newInstance();
        
        System.out.println(obj);
        
        /*
         * 정적 바인딩과 동적 바인딩의 차이
         * - 다운 캐스팅의 유무 (동적 바인딩 : X, 정적 바인딩 : O)
         * - 이유 : 동적 바인딩은 컴파일시 해당 클래스의 이름을 사용할 수 없기 때문임
         *             (매개변수로 클래스 이름을 넣는게 아니라 위치만 넣으니까)
         *             동적 바인딩은 멤버 메소드를 호출할 수 없다
         * 
         *     (중요) => 이 때, java.lang.Reflection 패키지의 Class 클래스를 이용하여
         *            다운캐스팅 할 수 없는 객체여도 모든 작업을 할 수 있게 지원해줌 (ex. getContstructors())
         */           
    }
}
cs

<동적 바인딩 예제>

'BackEnd > Java' 카테고리의 다른 글

자바 기본 정리  (0) 2017.02.09
Java :: startsWith() vs indexOf() vs charAt()  (0) 2016.12.26
Java :: Exception 예외처리  (0) 2016.12.15
Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22
Java :: Abstract vs Interface  (0) 2016.10.28

1. java.lang.Trowable

ㄱ. Error : 프로그램 실행 중 일어날 수 있는 치명적인 오류. 복구 불가능

ㄴ. Exception : 에러보다 비교적 경미한 오류. 프로그램의 비정상적 중단을 막을 수 있음

a. RuntimeException

b. Exception

 

 

2. RuntimeException

코드 논리의 오류. 컴파일시 체크되지 않고, 실행 도중 예외 발생시 비정상적으로 종료됨

코드를 수정하여 예외 발생을 막을 수 있음

대부분의 런타임 예외는 실행 중 조건의 문제보다는 코드의 논리적인 오류의 경우에 의해 발생함

 

1
2
3
4
5
6
7
8
9
10
11
package spms.test;
 
public class TestMain {
    public static void main(String[] args) {
        int x = 10;
        int y = 0;
        int z = x / y; //0으로 나눈 값이기 때문에 논리적 오류가 발생함
        
        System.out.println("debug> z : " + z);
    }
}
cs

  

3. Exception

실행 도중 필요한 리소스 파일이 없거나, 사용 매체의 문제 등으로 발생하는 예기치 못한 예외들

자바는 try ~ catch 문으로 예외 처리를 해야만 컴파일을 성공시킨다

 

try문에서 예외 발생시 JVM(Java Virtual Machine)은 그 예외가 어떤 것인지 분석하고 그 예외를 담을 수 있는 객체를 만들어서 참조함

=> catch 문은 try문에서 발생한 예외 객체를 인자로 받아와 catch문 내에서 사용

 

* Exception과 Error를 구분하는 기준 : JVM의 겉과 속

ㄱ. 겉 : Exception

ㄴ. 속 : Error

 

* try ~ catch 문에 return이 있다 하더라도 finally문은 반드시 실행된다

* 런타임 예외가 아닌 Exception일 경우 컴파일러는 에러를 발생시킨다

* 한 개의 try문에서 여러 개의 예외가 발생할 시에는 여러 개의 catch를 사용한다

=> 첫 번째 catch문에서 예외의 최상위인 Exception 매개변수를 받게 되면, 두 번째 catch문 부터는 받을 예외가 없어 컴파일 에러가 발생하게 됨

 

* 자바 7.0부터 지원하는 다중 catch 방식

A와 B Exception이 발생했을 때, 동일한 문구를 출력해야 함에도 불구하고 각각의 catch를 써야 함 => 중복 발생

 

1
2
3
4
5
6
7
8
9
    try {
            //예외 발생
        } catch (AException e) {
            System.out.println("예외 발생!");
        } catch (BException e) {
            System.out.println("예외 발생!");
        } catch (CException e) {
            e.printStackTrace();
        }
cs

<중복 예외를 처리하던 기존 자바 코드>

 

1
2
3
4
5
6
7
    try {
            //예외 발생
        } catch (AException || BException e) {
            System.out.println("예외 발생!");
        } catch (CException e) {
            e.printStackTrace();
        }
cs

<자바 7.0부터 지원하는 다중 catch 방식>

 

 

4. Finally

* finally를 가장 잘 활용하는 사례 : IOStream / DB Connection

ㄱ. IO (Input Output) Stream

가비지 컬렉션의 대상이 아닌 것 (가비지 컬렉션 : 자바의 JVM에서 모든 객체를 자동으로 소멸시켜주는 기능)

=> IO Stream 객체들은 개발자가 직접 닫아줘야 함

 

* IO Stream 객체 생성 후, 사용 중 에러가 발생하여 프로그램을 종료시 가비지 컬렉터의 대상이 아니기 때문에 메모리 누수의 원인이 될 수 있음

=> finally 블록을 꼭 추가하고 블록 안에서 IO Stream 객체를 소멸시키는 코드를 넣어야 함

 

 

5. Throw

DB 서버를 연결시 DB 서버에서 접속했다가 사용을 끝내면 자동 접속 종료를 기다리기 전에 편의상 미리 닫아주는 것이 효율적일 때가 있음. 그럴 때 사용

ㄱ. throw : 개발자가 필요에 의해 강제로 발생시키는 예외 코드

메소드 내에서 상위 블럭으로 예외를 던짐

억지로 에러를 발생시킬 때에도 사용하지만, 현재 메소드 에러를 처리한 후 상위 메소드에 여러 정보를 줌으로서 상위 메소드에도 에러가 발생했다는 것을 감지할 수 있음

throw 에약어 뒤에 java.lang.Throwable 클래스를 상속 받은 자식 클래스의 객체를 지정해야 함

 

1
2
3
4
5
6
7
8
9
try {
        //예외를 처리하는 객체 메모리 생성
        Exception e = new Exception(" ");
            
        //JVM이 예외를 감지하도록 고의로 이벤트를 발생시킴
        throw e;
    } catch (Exception e) {
        //예외처리 코드
    }
cs

 

ㄴ. throws : 현재 메소드에서 상위 메소드로 예외를 던짐

첫 번째 메소드에서 예외 발생시 예외를 처리해버리면 그 후의 메소드들은 예외가 발생되었는지조차 모르기 때문에 자바에서는 throws 키워드를 사용함

예외를 자신이 처리하지 않고, 자신을 호출하는 메소드에게 책임을 전가함

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void test1() throws Exception {
    //예외를 발생시키는 코드
}
        
void test2() throws Exception {
            
}
        
void test3() {
    try {
        test2();
    }
    catch (Exception e) {
    //예외를 처리하는 코드
    }
}
cs

 

 

* 메소드 오버라이딩시 throws 예외처리

- 예외를 던지지 않거나

- 부모메소드보다 작거나 같은 범위에서 예외처리를 해야 함

(부모 메소드가 예외처리 되지 않은 상태인 경우 오버라이딩 된 메소드도 예외 처리를 할 수 없음)


'BackEnd > Java' 카테고리의 다른 글

Java :: startsWith() vs indexOf() vs charAt()  (0) 2016.12.26
Java :: Reflection 리플렉션  (0) 2016.12.18
Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22
Java :: Abstract vs Interface  (0) 2016.10.28
Java :: 간단한 JDBC 예제  (0) 2016.10.18

DD를 조작하여 서블릿에 정보를 전달하기 위한 용도의 인터페이스

 

1. ServletContext

하나의 context (application 범위) 내에서 다른 서블릿 간에 공유가 가능한 데이터

 

a. getServletContext()

ㄱ. jsp에서 사용할 시 : context를 받아오는 용도로 사용
              (ex. ServletContext context = getServletContext(); )
ㄴ. MVC(model2)에서 사용할 시 : Controller의 인터페이스(서블릿의 인터페이스 - GenericServlet)을 받아 사용하게 됨
                                         웹 어플리케이션의 절대 경로를 구하는 servletContext()를 구할 수 있음
                                         (ex. String realFolder = context.getRealPath("upload")


b. request.getSerlvetContext() vs request.getSession().getServletContext() 차이
     session이든 request든 간에 하나의 ServletContext 범위 안에서(하나의 웹 어플리케이션 영역)에 있음
     => 같은 ServletContext를 리턴하기 때문에 실질적인 둘의 차이는 없다


c. 서버의 물리적 경로 구하기
    - 현재 서비스가 돌아가고 있는 서버의 웹서비스 디렉토리 물리 경로를 구할시 사용 (파일 업로드시)

ㄱ. 업로드 디렉토리가 웹서비스 디렉토리 하위에 위치한 경우
    ( ex. request.getSession().getServletContext().getRealPath("/") )
        - 업로드 url : http://localhost\upload
        - 업로드 디렉토리 물리적 경로 : C:\Web\WebContents\upload\
        - 웹서비스 경로 : C:\Web\WebContents\
            - 가장 일반적 방법. 현재 서비스가 돌아가고 있는 서블릿의 경로를 가져옴.
            - 파일 업로드 위치가 실제 업로드 디렉토리 물리적 경로와 같이 서블릿 구동 경로 안에 있는 디렉토리에 포함되어 있을 경우 사용          
 ㄴ. 업로드 디렉토리가 별도 존재 => Tomcat 등의 Context로 추가한 경우
     ( ex. request.getSession().getServletContext().getContext("/upload").getPath("") )
        - 업로드 url : http://localhost\upload
        - 업로드 디렉토리 물리적 경로 : D:\upload\
        -  웹서비스 경로 : C:\Web\WebContents\
            - 업로드 디렉토리가 물리적으로 웹서비스 디렉토리에 포함되지 않고 별도로 존재함
            - 해당 디렉토리는 WAS 상에서 Context 등을 통해 별도로 추가된 경우 사용
 ㄷ. Properties 파일에 실제 저장될 물리적 경로 기입한 경우
        - 최근 가장 많이 사용하는 방법
        - WAS에 따라 처리하는 방식이 조금씩 다르기 때문에 편의성을 위해 사용

 

* ReadOnly : DD에서 config는 <servlet> 내에 있었지만, 개념적으로 Context가 더 상위이기 때문에 위치도 <servlet>보다

  위여야 함

  <coxntext-param>~</context-param> 에서 가져올 땐 getInitParam() 메소드를 사용함

  ReadWrite : getAttribute(), setAttribute() 메소드를 사용하여 특정 scope 조정하여 데이터 공유 가능


 

2. ServletConfig

해당 서블릿에서 사용함

하나의 서블릿에 관련된 초기화 파라미터

=> 주로 그 서블릿의 초기화 파라미터 값들을 설정하고 저장할 수 있음 (파라미터 초기화 : DD 사용)

 

'BackEnd > Java' 카테고리의 다른 글

Java :: Reflection 리플렉션  (0) 2016.12.18
Java :: Exception 예외처리  (0) 2016.12.15
Java :: Abstract vs Interface  (0) 2016.10.28
Java :: 간단한 JDBC 예제  (0) 2016.10.18
Java :: 스레드(Thread)  (0) 2016.10.12

1. Abstract (추상 클래스)

반드시 한 개 이상의 추상 메소드를 가지고, 객체를 생성하지 않는다.

슈퍼 클래스로 사용이 가능하며 추상 메소드가 하나 이상만 있으면 된다. 

 

 

2. Interface (인터페이스)

서로 다른 클래스를 연결시켜주는 연결 장치이다.

슈퍼 클래스의 용도로 사용이 가능하며, 반드시 추상 메소드로만 구현되어야 한다.

 

 

* Class > Abstract > Interface

 

 

3. 차이점

 

 Abstract

Interface 

추상 메소드 유무

1개 이상의 추상 메소드

전부 추상 메소드 

상속 유무

단일 상속만 가능 

다중 상속 가능 

 

 

4. DTO 에서 Interface를 사용하는 이유

프로그램 설계시 클래스의 구조가 1번의 경우일 때에는 A부터 C까지 쭉 상속을 받아 단일 상속으로 가능한 Abstract로 구현하면 되지만, 2번의 경우일 때에는 관련 없는 D 클래스가 있는 경우도 있기 때문에 보통은 Interface를 사용한다.

(2번 같은 경우에는 B를 상속받고 D를 인터페이스로 사용한다)

'BackEnd > Java' 카테고리의 다른 글

Java :: Exception 예외처리  (0) 2016.12.15
Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22
Java :: 간단한 JDBC 예제  (0) 2016.10.18
Java :: 스레드(Thread)  (0) 2016.10.12
Java :: Code vs Heap vs Stack  (0) 2016.10.10

1. 웹 어플리케이션 구조

 

 

2. m_insert_form.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html>
 
<%= request.getRequestURI() %> <br>
 
<form action="<%= request.getContextPath() %>/minsert/m_insert_pro.jsp" method="post">
 
<table border="1">
    <tr>
        <td>아이디</td>
        <td><input type="text" name="m_id" size="20"></td>
    <tr>
    <tr>
        <td>암호</td>
        <td><input type="text" name="m_pw" size="20"></td>
    <tr>
    <tr>
        <td>권한</td>
        <td><input type="text" name="m_level" size="20"></td>
    <tr>
    <tr>
        <td>이름</td>
        <td><input type="text" name="m_name" size="20"></td>
    <tr>
    <tr>
        <td>이메일</td>
        <td><input type="text" name="m_email" size="20"></td>
    <tr>
    <tr>
        <td colspan="4"><input type="submit" value="회원가입버튼"></td>
    </tr>
</table>
 
</form>
cs

 

 

3.  m_insert_pro.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html>
<!-- Connection 객체, PreparedStatement 객체 사용하기 위해서는 import를 해줘야 함 -->
<!-- DriverManage와 SQLException(쿼리문 사용) 객체 사용하기 위해서도 import 해줘야 함 -->
<%@ page import = "java.sql.DriverManager" %>
<%@ page import = "java.sql.Connection" %>
<%@ page import = "java.sql.PreparedStatement" %>
<%@ page import = "java.sql.SQLException" %>
 
<!-- 
    JDBC(Java Database Connectivity) : 자바 언어를 이용해 DB에 접근할 수 있는 API 묶음 
        * API : java.sql.Connection 으로 정의되어 있음(java.sql.~ 클래스들 import 해줘야 함)
        1. DB 주소 + 포트번호 + 이름 + 암호 이용해서 연결(Connection) 객체 생성
        2. 커넥션에서 sql 객체 생성
        3. sql 객체 이용하여 sql 작업을 함
        4. 사용했던 리소스들(sql 객체, 커넥션 등)을 해제
-->
 
<!-- 자바 소스 코드가 들어가야 하기 때문에 스크립트릿 안에 자바 소스 코드를 넣었음 -->
<%
//  console 창에 출력하기 전 form.jsp에서 받은 파라미터 값들이 깨지지 않도록 인코딩
    request.getParameter("utf-8");
    
//  Connection, PreparedStatement 객체 생성
//  선언만 해주고 초기화 해주지 않을 시 => nullPointException 일어날 가능성 있음
    Connection conn = null;
//  PreparedStatement와 Statement의 차이
//  1. PreparedStatement : 쿼리문이 들어갈 양식만 있음 
//  2. Statement : 쿼리문 통째로 집어넣음
    PreparedStatement pstmt = null;
    
//  form의 파라미터들을 request 내장 객체 getParameter 메소드로 받아와 String형 변수들로 대입함
    String m_id = request.getParameter("m_id");
    String m_pw = request.getParameter("m_pw");
    String m_level = request.getParameter("m_level");
    String m_name = request.getParameter("m_name");
    String m_email = request.getParameter("m_email");
    
    System.out.println(m_id + "<-- m_id /minsert/m_insert_pro.jsp");
    System.out.println(m_pw + "<-- m_pw /minsert/m_insert_pro.jsp");
    System.out.println(m_level + "<-- m_level /minsert/m_insert_pro.jsp");
    System.out.println(m_name + "<-- m_name /minsert/m_insert_pro.jsp");
    System.out.println(m_email + "<-- m_email /minsert/m_insert_pro.jsp");
    
//  JDBC 드라이버 로딩(mysql이기 때문에 mysql, jdbc 형식이기 때문에 jdbc라고 적어줘야 함)
    Class.forName("com.mysql.jdbc.Driver");
    
//  해당 예제의 try문에는 catch가 없는데, 이것은 예외처리를 따로 해줄 필요가 없기 때문이다.
//  (catch가 없는 경우에는 try~finally 문을 굳이 써야할 필요가 없음 => try~finally 없애도 됨)
    try{
//      드라이버 주소, db id, db password가 필요(인코딩은 해줘도, 안 해줘도 됨)
        String jdbcDriver = "jdbc:mysql://localhost:3306/dev22db?" + 
                            "useUnicode=true&characterEncoding=utf8";
        String dbUser = "dev22id";
        String dbPass = "dev22pw";
        
//      mysql 커넥션 연결
//      커넥션 정보가 담긴 return 값을 conn이라는 인스턴스 주소값에 대입
//      매개변수 안에 직접 드라이버 주소, db id, db password를 적어줘도 되지만 매개변수 값의 길이가
//      너무 길기 때문에 밖에 따로 변수로 선언
        conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
 
        System.out.println("console> conn : " + conn);
    
//      mysql 쿼리문 선언
//      PreparedStatement 객체를 사용하는 이유는 ? 안에 들어가는 파라미터 값들이 
//      계속 변할 수 있으므로, 일일히 쿼리를 수정하는 것보다는 PreparedStatement 객체를
//      사용함으로서 form에서 받아오는 파라미터 값들을 유연하게 대처할 수 있기 때문이다.
        pstmt = conn.prepareStatement("INSERT INTO tb_member VALUES (?, ?, ?, ?, ?)");
        
//      콘솔창에서 확인해보면 ?가 들어간 쿼리문만 출력됨
        System.out.println("console> before pstmt : " + pstmt);
        
//      form.jsp에서 받는 파라미터의 갯수대로 setting을 해준다.
//      (form에서 받는 파라미터들은 모두 default string 형으로 받아오기 때문에 setString 메소드를 호출해야 함)
        pstmt.setString(1, m_id);
        pstmt.setString(2, m_pw);
        pstmt.setString(3, m_level);
        pstmt.setString(4, m_name);
        pstmt.setString(5, m_email);
        
//      파라미터들을 setting 해준 뒤이기 때문에, 콘솔창에서 확인해보면 쿼리문 안에
//      setting 해준 값들이 쿼리문에 같이 출력됨을 알 수 있음
        System.out.println("console> after pstmt : " + pstmt);
    
//      쿼리 실행(쿼리문에서 직접 값을 받아오지 않는 경우만 사용 가능)
//      쿼리 실행 후 값을 직접 받아와야 하는 경우
//      (ex. SELECT문 => ResultSet 객체 선언하고 사용, 인스턴스.executeQuery() 메소드 사용)        
        pstmt.executeUpdate();
    
    }finally{
//      실행되었던 커넥션들을 모두 닫아줘야 함(객체 선언한 순서의 반대로 닫아줘야 함)
        if (pstmt != nulltry { pstmt.close(); } catch(SQLException ex) {}
        if (conn != nulltry { conn.close(); } catch(SQLException ex) {}
    }
%>
cs

 

 

 

 

4. 결과 

'BackEnd > Java' 카테고리의 다른 글

Servlet :: ServletContext vs ServletConfig  (0) 2016.11.22
Java :: Abstract vs Interface  (0) 2016.10.28
Java :: 스레드(Thread)  (0) 2016.10.12
Java :: Code vs Heap vs Stack  (0) 2016.10.10
Java :: 자바 소켓 프로그래밍(TCP)  (0) 2016.10.09

1. 정의

- 한 프로세스 내에서 두가지 또는 그 이상의 일을 동시에 할 수 있는 것 (동시에 두 가지 이상의 루틴 실행 가능함)

- 앞 뒤 순서 없는 일들이 있고 그 일들을 분리해서 동시에 처리해야 할 때 주로 사용

- 작은 규모의 프로세스. 다수 개의 스레드는 하나의 프로세스에서 나타남

- 자바에서 사용시 반드시 스레드를 상속받아 사용해야 함 (가장 대표적인 스레드 구동 방법)

- 모든 스레드는 해당 프로세스의 데이터 공간을 공유함

  (main 메소드에서 인스턴스.start() 메소드를 호출시 객체 안에 있는 메소드 전부가 실행되도록 구동되어 있음)

- 프로세스를 function. 즉 메소드 단위로 실행시키는 것. 일부 코드만 별도로 분리하여 실행함

- 프로세스에 비해 경량.

- 객체화되는 클래스 내부에 있는 메소드가 오버라이딩 됨

  (부모 클래스인 스레드를 상속 받는 자식 클래스를 메인 클래스에서 호출하기 때문에 오버라이딩)

 

 

2. 단일 스레드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package lesson01;
 
import java.util.Random;
 
//단일 쓰레드를 받는 예제
//자바에서 쓰레드를 구동시키는 가장 기본적인 방법 : Thread 상속
//쓰레드를 상속 받는 클래스 내에 있는 메소드가 실행이 될 때도 있고 안될 때도 있음
//=> 병렬적 실행 
public class ThreadTest extends Thread {
    static int index = 0;
    int id = -1;
    
//  2-1번째로 실행
    public ThreadTest(int id) {
        this.id = id;
        
        System.out.println("cosnole> Contructor id : " + id);
    }
    
//  Thread 부모 클래스를 상속받은 자식 클래스인 ThreadTest 가 실행되는 것이기 때문에
//  main 메소드에서 ThreadTest 객체를 실행시키게 되면
//  run() 메소드는 오버라이딩 되는 것이라고 할 수 있음.
    public void run() {
        System.out.println("console> id : " + id + "번 쓰레드 동작 중 ...");
        
        Random r = new Random(System.currentTimeMillis());
        
        try {
//          0.3초를 long s에 대입시킴
            long s = r.nextInt(3000);
            
            System.out.println("console> s : " + s);
            
//          sleep(min) : 쓰레드를 정지시키는 메소드. min : 정지시킬 시간(초)
//          0.3초 동안 쓰레드를 정지시킴
            Thread.sleep(s);
            
            index++;
        }
//      예외처리
        catch (InterruptedException e) { 
            e.printStackTrace();
        }
        
        System.out.println(id + " 번 쓰레드 동작 종료 ...");
    }
    
    public static void main(String[] args) {
//      1번째로 실행
        System.out.println("console> Start main method.");
        
        for (int i = 0; i < 10; i++) {
//          2번째로 실행
//          ThreadTest 생성자의 id 변수값 초기화 시킴
            ThreadTest t = new ThreadTest(i);
            
//          3번째 실행
            System.out.println("console> for i : " + i);
            
//          start() : 해당 객체의 메소드를 차례대로 실행시킴.
//          쓰레드는 for문 안에 있던 없던 간에 순서를 지키지 않고 병렬적으로 실행되기 때문에
//          run() 메소드가 실행될 때도 있고 실행되지 않을 때도 있음.
            t.start();
        }
        
        try {
//          0.5초동안 쓰레드 정지시킴
            Thread.sleep(5000);

//        예외처리 

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("console> current Index : " + index);
        System.out.println("console> End main method.");
    }
}
cs

 

 

실행된 콘솔창을 보면, 총 3번을 run 했음에도 불구하고 출력되는 내용이 모두 다 다르게 나온다.

이유인 즉슨 스레드는 순서를 지키지 않은 채로 분리되어 실행되기 때문에 스레드로 오버라이딩 되는 run() 메소드 안에 있는 console> id : id번 쓰레드 동작 중.. 이라는 메세지가 출력될 때도 있고 출력되지 않을 때도 있는 것이다.

(스레드로 동작하는 run() 메소드가 구동될 때도 있고, 구동되지 않을 때도 있음 => 직렬적이 아니라 병렬적으로 동작하므로)

 

메인 메소드에서 for문 안에 있는 초기화된 값 i가 1씩 증가하는데도 불구하고 말이다.

 

 

3. 멀티 스레드

- 멀티 스레드를 이용하는 방법에는 두 가지가 있음

ㄱ. java.lang.Thread 클래스 이용

- 장점 : 스레드 클래스 메소드를 바로 사용 가능

- 단점 : 메인 클래스가 타 클래스의 자식 클래스인 경우 사용하지 못함

ㄴ. java.long.Runnable 인터페이스 이용

- 장점 : 타 클래스로부터 상속 받은 상태여도(자식 클래스인 상태여도) 그 클래스를 스레드로 사용 가능

- 단점 : 스레드 클래스의 메소드는 사용하지 못함

 

1
2
3
4
5
6
7
8
package lesson01;
 
public class Thread1Main extends Thread {
//  run() 메소드 오버라이딩
    public void run() {
        System.out.println("console> Thread 1");
    }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package lesson01;
 
public class Thread2Main extends Thread {
//  run() 메소드가 오버라이딩 됨
    public void run() {
        System.out.println("console> Thread 2");
    }
    
    public static void main(String[] args) {
        Thread1Main tm1 = new Thread1Main();
        Thread2Main tm2 = new Thread2Main();
        
//      start() : Thread를 상속 받는 자식 클래스의 모든 메소드들이 실행됨
//      스레드는 순서가 없이 병렬적으로 실행되기 때문에 tm1 인스턴스와 tm2 인스턴스가
//      순서 없이 실행됨을 확인할 수 있음
        tm1.start();
        tm2.start();
    }
}
cs

 

여러 번 run을 해본 결과, 콘솔 창에 출력되는 값들은 순서가 일정하지 않았다.

멀티 스레드를 이용할 시 스레드가 여러 개 있어도 순서를 지키지 않고 제멋대로 실행이 된다는 것을 확인할 수 있다.

* 응용 프로그램이 실행되면 JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당 받고, JVM은 메모리를 용도에 따라 여러 영역으로 나누어서 관리한다.

 

 

1. 코드 (Code) 영역

컴파일된 .class 코드 영역 (=클래스 영역 / 코드 영역 / 메소드 영역 - 이라고도 불린다)

0과 1로 된 2진수(binary)

static 변수 / static 메소드 (= static 영역이라고도 불린다) : class가 실행되기 전에 미리 메모리가 확보됨

 

 

2. 스택 (Stack) 영역 ( <=> 큐 )

가장 늦게 들어온 것부터 처리함

(ex. 함수 / 메소드 => A a = new B(); 시 B() 생성자 메소드를 호출하는게 아닌 뒤늦게 만들어진 인스턴스 a를 호출하는 것)
main() 메소드가 가장 먼저 호출됨 (지역변수를 저장할 메모리가 필요하니까)

 

 

3. 힙 (Heap) 영역

객체 인스턴스 (new 키워드가 들어가는)는 무조건 heap에 만들어짐 (생성자 메소드)

호출되는 클래스 내의 메소드들도 저장됨

 

* 만들어지는 순서 : code > stack > heap

* 종료되는 순서 : heap > stack > code

 

 

4. 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.java;
 
//CallStackTest : method area
public class CallStackTest {
//  str : stack(정적 메모리)
    String str = "홍길동";
    
//  main method : call stack(정적 메모리)
    public static void main(String[] args) {
//      main method에서 firstMethod() 메소드를 호출했기 때문에 먼저 호출됨
        System.out.println("console> main method() 시작");
        
        firstMethod();
        
        System.out.println("console> main method() 끝");
    }
    
//  firstMethod() method : Heap(동적 메모리)
    public static void firstMethod() {
        System.out.println("console> firstMethod() 시작");
        
        secondMethod();
        
        System.out.println("console> firstMethod() 끝");
    }
    
//  secondMethod() method : Heap(동적 메모리)
    public static void secondMethod() {
        System.out.println("console> secondMethod()");
    }
}
cs

 

 

'BackEnd > Java' 카테고리의 다른 글

Java :: 간단한 JDBC 예제  (0) 2016.10.18
Java :: 스레드(Thread)  (0) 2016.10.12
Java :: 자바 소켓 프로그래밍(TCP)  (0) 2016.10.09
Java :: 업캐스팅(UpCasting) vs 다운캐스팅(DownCasting)  (0) 2016.10.05
Java :: final과 static  (0) 2016.09.30

+ Recent posts