이거만 하면 자바는 바이바이

stream 메소드 정리하면서 람다식도 다시한번 더 정리 해 보자!!

 

출력할 때 

stream 메소드에서 반복문을 처리하는 foreach문이 있는데 출력 할 때도 이 반복을 이용할 수 있음!!

출력할 때 주로 System.out.println 를 많이 이용 했는데 foreach 문을 사용하면

~~~ .forEach(System.out::println) 로 쉽게 출력이 가능 해 짐

 

public class Stream02 {

	public static void main(String[] args) {
		

		System.out.println("[스트림 객체의 주요 메소드]");    	
        
          //map(): 스트림의 각 요소를 람다식을 적용 해 변경하는 함수    	
        System.out.println("1.map()함수");
		IntStream stream =IntStream.rangeClosed(1,5);  //(1,2,3,4,5가 있음)
		stream.map(e->e*e).forEach(x->System.out.println(x));  // foreach 기능 다시 공부!!!		
        //스트림은 한번 써서 이제 닫힘 다시 새로운 stream 생성 해야 함
        
		  //reduce(): 스트림의 요소를 줄이는 함수 
        //ex)3x3 표에 sum 을 하면 결과가 1개 나옴 이런것도 reduce임
		System.out.println("2.reduce()함수 ");
        System.out.println(IntStream.range(1,6).reduce((e1,e2)->e1+e2));  //OptionalInt[15]
		System.out.println(IntStream.range(1,6).reduce((e1,e2)->e1+e2).getAsInt()); // getAsInt()는 숫자만 나오게 해줌
		
        System.out.println("3.limit() 함수");
	//	IntStream.rangeClosed(1,5).limit(3).forEach(x->System.out.println(x));  //출력 시 이거보단
		IntStream.rangeClosed(1,5).limit(3).forEach(System.out::println);    // 이렇게 씀!
	
	      //skip() 스트림의 최초 요소부터 설정한 요소 수까지 제외하고 새로운 stream 반환
		System.out.println("4.skip() 함수");   
		IntStream.rangeClosed(1,5).skip(3).forEach(System.out::println);  // 1~3 스킵!

        System.out.println("5.distinct() 함수");  // 중복요소를 제거한다
		Arrays.asList(1,2,5,4,2,3,2,5,1,1).stream().distinct().sorted()  
		.forEach(System.out::println);
        
         //filter() : 조건을 만족하는 요소만 스트림 반환
		System.out.println("6.filter() 함수");
		IntStream.rangeClosed(1,10).filter(x->x%2==0).forEach(System.out::println); // 1~10까지 짝수만
		
		System.out.println("7.count() 함수");  // 개수 세기
		System.out.println(IntStream.rangeClosed(9,999).filter(x->x%2!=0).count());//9~999 중 홀수인 숫자의 개수
				
		System.out.println("8.sum() 함수");  // 총합 구하기
		System.out.println(IntStream.rangeClosed(1,10).filter(x->x%2 ==0).sum());
		
		System.out.println("9.max() 함수");
		System.out.println(IntStream.rangeClosed(1,10).max().getAsInt());
	
		System.out.println("10.min() 함수");
		System.out.println(IntStream.rangeClosed(1,10).min().getAsInt());
		
        System.out.println("11.findAny() 함수"); // 설정한 값 사이에서 랜덤하게 출력
		System.out.println(IntStream.rangeClosed(2,1000).findAny().getAsInt());
		
		System.out.println("12.findfirst() 함수"); // 첫번째만 출력
		System.out.println(IntStream.rangeClosed(1,10).findAny().getAsInt());
        
        //문제1~100 까지 숫자 중 50 이상 이고 홀수 이면서 5의배수인 수의 합을 구하라
		// 람다식과 스트림만 이용
		System.out.println("[스트림 미 사용]");
			int sum = 0;
			for(int i=0; i<=100 ; i++) {
				if(i>=50 && i%5 ==0 && i%2 !=0) sum += i;
			}
		  	System.out.println(sum);
			
		System.out.println("[스트림 사용]");
	    	System.out.println(IntStream.rangeClosed(1,100).filter(x->x>=50 && x%2!=0 && x%5==0).sum());
	    	System.out.println(IntStream.rangeClosed(1,100).skip(49).filter(x->x%2!=0 && x%5==0).sum());//방법2
	    	System.out.println(IntStream.rangeClosed(1,100).filter(x->x>=50).filter(x->x%2!=0).filter(x->x%5==0).sum());//방법3	
		
		
		
        
}//////////main
}///class

'학원 > JDBC' 카테고리의 다른 글

10/25 28-8 Stream  (0) 2022.10.25
10/25 28-7 lambda  (1) 2022.10.25
10/25 28-6 람다식 과 Stream 이론 정리  (1) 2022.10.25
10/25 28-5 Generic 코딩으로 알아보기  (0) 2022.10.25
10/25 28-4 제너릭(Generic) 이론정리  (0) 2022.10.25

정렬 위주...

public class Stream01 {
	public static void main(String[] args) {
    	  System.out.println("[데이터 소스:배열]");
          String[] mountains= {"한라산","지리산","덕유산","치악산","설악산"};
          //배열의 데이터를 처리하기 위한 stream객체 생성
          Stream<String> stream1 = Arrays.stream(mountains);  //stream()은 제너릭 메소드
    	  stream1.forEach(x-> System.out.println(x)); // 이건 출력O 출력 후(최종 연산 후) stream 닫힘.
    	 // stream1.forEach(y-> System.out.println(y));  출력 안됨 그래서 stream 다시 만들어야 함 
    	 // Arrays.sort()로 배열 정렬 :원본 변경됨
            Arrays.sort(mountains);
	          for(String m : mountains) System.out.println(m);
              
          System.out.println("[stream 객체의 soreted()로 배열정렬:원본배열 변경x]");
          stream1 = Arrays.stream(mountains);
    	  stream1.sorted().forEach(y-> System.out.println(y)); //디폴트가 오름차순
    	  stream1.sorted((x,y)->y.compareTo(x)).forEach(y-> System.out.println(y));// 내림차순 정렬
    
    	  System.out.println("[데이터 소스:컬렉션]");
          List<String> lists = Arrays.asList(mountains);
          lists.stream();    //스트림객체
    	  Stream<String> stream2 = lists.stream();
          System.out.println("[Collections.sort()- 원본컬랙션변경]");
          Collections.sort(lists);
          
          System.out.println("[스트림객체의 sorted()- 원본컬랙션변경x]");
	      stream2.sorted().forEach(x->System.out.println(x));
	      System.out.println("내림차순");
	      stream2.sorted((x,y)->y.compareTo(x)).forEach(x->System.out.println(x));
	      System.out.println("[원본]");
	      for(String m : lists) System.out.println(m);
    }////////m
}/////c

람다식 해보죠

 

함수형 인터페이스는 추상 메소드를 하나만 갖는다
인터페이스에 @FunctionalInterface 어노테이션을 붙이면 그 인터페이스는 함수형 인터페이스가 되어 무조건 추상메소드를 하나만 가져야한다.

 

인터페이스 생성

//인터페이스

	@FunctionalInterface   // 있어도 없어도 됨 아래 인터페이스는 함수형이라는 걸 알려주는 표시
	public interface MyInterface {
		
	int calc(int a, int b);
    
	//void a();   놉! 이거안돼! 추상메소드 하나만 가능해!

인터페이스를 상속받은 클래스 생성

public class MyInterfaceImpl implements MyInterface{
	// + 기능 하나만 정의 가능
	@Override
	public int calc(int a, int b) {	
		return a+b ;
	}		
}

메소드구현

public class MyCalculator {

		// 인자에 람다식(익명함수)을 받는 메소드
        static void paramMethod(MyInterface lambda,int a, int b){
        	 System.out.println(lambda.calc(a, b));
        }
        
        //람다식을 반환하는 메소드
        static MyInterface returnMethod(int z){
        	return(x,y) -> x*y+z;
        }

	public static void main(String[] args) {
    	
        //방법1. 인터페이스를 구현 한 클래스 사용:더하기만 가능, 재사용도 가능(MyInterfaceImpl타입 객체 또 생성가능)
    	System.out.println("[인터페이스를 구현한 클래스 사용:더하기만 가능]");
        MyInterface my1 = new MyInterfacelmpl();
         System.out.println(my1.calc(10, 5));
                          
        //방법2. 익명 클래스로 구현, 즉 별도의 클래스 필요x  코드 간결, 재사용은 불가
        System.out.println("[익명 클래스 사용:다른 연산 가능]");
        MyInterface my2 = new MyIntrerface(){
         		@Override
				public int calc(int a, int b) {			
				    return a+b;
				}			
         };
          System.out.println(my2.calc(10, 5));	
          
             my2 = new MyInterface() {		
			    @Override
			    public int calc(int a, int b) {				
				     return a-b;
			      }		
		 };
          System.out.println(my2.calc(10, 5));
     
        //방법3. 람다식 사용.클래스 불필요.방법2 보다 코드 더 간결. 단, 재사용은 불가. 추상 메소드 하나로 다양한 기능 구현.
          System.out.println("람다식 사용: 다른 연산 가능");
          //※람다식은 MyInterface의 추상메소드 형태여야한다
            MyInterface lambda = (a,b) -> a+b;
          	  System.out.println(lambda.calc(10,5));
              lambda = (a,b) -> a-b;
          	  System.out.println(lambda.calc(10,5));
              lambda = (a,b) -> a*b;
          	  System.out.println(lambda.calc(10,5));
              lambda = (a,b) -> a/b;
          	  System.out.println(lambda.calc(10,5));
         //람다식(익명함수)을 메소드의 인자로 전달
         	  lambda = (a.b) -> a%b;
               paramMethod(lambda,10,3);
          //   paramMethod( (a,b) -> a%b ,10,3); 굳이 변수에 안담고 요렇게도 당연 가능!!
               
          //람다식을 반환하는 메소드      
               System.out.println(returnMethod(10).calc(10,5));
 
		}///m	
}//////c

람다식 

 

람다람다람쥐?

앞에 제너릭하느라 정신을 빼놔서 드립칠 생각도 못했다... 하

아무튼 람다식은 또 뭐냐 후려처서 말하면 이름이 없는 함수를 표현하기 위한 언어라고 한다.

익명함수, 함수명(메소드명)이 없는 함수를 생성하기 위한  표현식으로 함수형 언어에서 사용하는 함수 표현방법이다

( cf.자바는 객체지향언어! 파이썬은 함수형언어! )

 

[함수형언어의 특징]

함수를 일급객체로 다룬다....? 그말은 함수를 변수에 넣을 수 있다= 매개변수로 함수를 전달하거나, 함수를 반환 할 수 있다는 뜻 아하!
대신 함수는 순수함수여야함(외부 변수의 영향 받지 않는 함수)

람다식은 인터페이스의 추상 메소드를 간결하게 그리고 하나의 추상 메소드로 여러가지 기능을 갖는 다양한 일회성 익명함수를 구현하는 것이 목적이다

추상 메소드를 하.나.만. 갖는 인터페이스(함수형 인터페이스라 함)가 반.드.시. 필요하다.  
@FunctionalInterface로 인터페이스를 만드는 경우, 하나 이상의 추상메소드 정의 시 컴파일 에러가 발생한다
****컬렉션이나 배열의 데이타를 다루고 Stream객체의 메소드 인자로 전달할 때 많이 사용한다 ***

 

[람다식]

(매개변수들) ->  {    ...  }    

람다식은 함수를 간.결.하.게 표현하기 위해 많은 생략 기법을 사용 하다보니 진짜 엄청 간단하네
1.매개변수의 자료형 생략 가능.
2.매개변수가 한 개인 경우 매개변수를 감싸는 괄호를 생략 가능
3.함수 구현부에 명령문이 한 개인 경우 구현부를 감싸는 중괄호 생략 가능
4.함수 구현부에 명령문이 한 개이고 그 명령문이 return문일 경우  return도 생략 가능.
5.매개변수가 없거나 두 개 이상 일 때는 무조건 괄호로 감싸야 한다

 

Stream

배열이나 컬렉션의 저장된 객체(데이터)를 변경하지 않고 처리하기 위한 라이브러리로 "지연연산"(=Lazy Evaluation )을 수행한다.

음.. 오라클에서 커밋이나 롤백 하기 전에 데이터를 메모리에 임시보관하는 그런느낌???

스트림의 메소드의 인자로 람다식을 전달하면 코드를 훨씬 간결하게 작성 할 수 있다 
스트림의 메소드는 "내부 반복"으로 데이타를 처리한다. 즉 for문이나 while문과 같은 반복문을 명시적으로 사용하지 않는다. 우와아아아아
스트림은 한 번 사용하면 닫혀서 다시 사용할 수 없다. 다시 사용하려면 Stream객체를 다시 얻어 와야 한다
Stream는 범용적인 Stream <T> 와 데이터 소스로 기본 자료형을 다루는 IntStream, LongStream, DoubleStream을 제공한다

 

 

[스트림 생성 ]: 스트림의 데이터 소스은 주로 배열과  컬렉션(근데  MAP계열은 없어용 )을 사용한다

 

범용적인 스트림 생성
-컬렉션인 경우
     Stream<T> 컬렉션객체.stream()      // map은 없어용
-배열인 경우
    Stream<T> Stream.of(T[])
    Stream<T> Arrays.stream(T[])
    Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)

 

int, long, double과 같은 기본 자료형 배열을 소스로 하는 스트림 생성
    IntStream IntStream.of(int...values)
    IntStream IntStream.of(int[])
    IntStream Arrays.stream(int[])
    IntStream Arrays.stream(int[] array, int startInclusive, endExclusive)

 

****특정 범위의 정수를 소스로하는 스트림 생성 ********        range 많이 씀..........
IntStream IntStream.range(int startInclusive, endExclusive);                    //끝 숫자 제외
IntStream IntStream.rangeClosed(int startInclusive, endInclusive);          //끝 숫자 포함

 

[스트림의 주요 메소드]

스트림의 메소드는 스트림의 데이터를 변환하는 중간 연산을 하는 메소드와 스트림 데이타를 사용하는 최종연산으로 나눌 수 있다. 중간 연산 메소드는 연속해서 사용이 가능하나 최종 연산 메소드는 사용 후 스트림이 닫히기 때문에 새롭게 스트림을 생성해야 한다.

중간 연산 메소드:  (저장 전)
Stream <T> distinct() : Stream의 중복 요소 제거 바로 실행x 지연연산!
Stream <T> sorted([Comparator]) : Stream 요소를 오름차순으로 정렬, 람다식으로 Comparator를 구현하여 오름차순 및 내림차순으로 정렬 할수 있다
Stream <T> filter(Predicate <T> predicate) : 조건에 만족하는 요소를 Stream으로 생성
Stream <T> limit(long maxSize) : maxSize 까지의 요소를 Stream으로 생성
Stream <T> skip(ling n) : n개까지의 요소를 제외하는 stream 생성
Stream <R> map(Function< ? super T, ? extends R> mapper) : 입력 T타입을 R타입 요소로 변환한 스트림 생성 

<? extneds T>  요게 T타입을 상속받은 ? 모든 객체들 요런 뜻

map => 변형하는거라 생각!

 

최종 연산 메소드:  집계(완전 저장)
T reduce ( T identity, BinaryOperator<T> accumulator) : Stream 의 요소를 하나씩 줄여가며 연산.
void forEach(Consumer <? super T> action) : Stream 의 각 요소에 지정된 작업 수행
long count() :  Stream 의 요소 개수 반환
Optional <T> sum (Comparator <? super T> comparator) : Stream 의 요소 합 반환
Optional <T> max (Comparator <? super T> comparator) : Stream 요소의 최대 값 반환
Optional <T> min (Comparator <? super T> comparator) : Stream 요소의 최소 값 반환
Optional <T> findAny() : Stream 요소의 랜덤 첫 번째 요소 반환(불안정)
Optional <T> findFirst() : Stream 의 첫 번째 요소 반환(안정적)

 

스트림은 컬렉션 정렬할 때 슬쩍 맛보기로 대충 하고 넘어 간 적 이 있음! 지금보면 쪼오오오금은 이해 될 거니까 그거 복습하고 오세욤!

CollectionNArraySort 여기랑 또 연결 되어있는게 InnerAnonymousClass 요 부분 공부하면 이해 될 것!!

'학원 > JDBC' 카테고리의 다른 글

10/25 28-8 Stream  (0) 2022.10.25
10/25 28-7 lambda  (1) 2022.10.25
10/25 28-5 Generic 코딩으로 알아보기  (0) 2022.10.25
10/25 28-4 제너릭(Generic) 이론정리  (0) 2022.10.25
10/25 28-3 TransationSQL(트랜젝션처리)  (1) 2022.10.25

코딩을 치면 좀 알게될 까?

public class MyGeneric<T> {
	private T field;
//	public static T staticField;    // 정적 필드에는 타입파라미터 안된다!!!

	public T getField() {
		return field;
	}

	public void setField(T field) {
		this.field = field;
	}
	
//	public static T staticMethod() {return field;} 안돼용 정적메소드는 타입 파라미터 불가! 단 제너릭 메소드에는 static 사용가능
//	public static void saticMethod(T field) {} 타입파라 노노
	
	//제너릭메소드(정적).인스턴스화 없이 클래스명으로 접근
	public static <T> T getEndValue1(T...t) {
		for(int i=0 ; i < t.length ; i++) System.out.println(t[i]);		
		return t[t.length-1];
	}
	//제너릭메소드(인스턴스화).인스턴스화 해서 변수로 접근
	public  <T> T getEndValue2(T...t) {			
		return t[t.length-1];
//		return field;   메소드의 T가 저 맨 위(MYGENERIC)의 T가아님!!
	}
	
	//[타입제한하기]
	// 일반 메소드로 메소드 파라미터의 타입제한  <? extends Number> ==숫자로 제한한다!!
	// 요소의 모든합을 구하는 메소드
	public static void nonGenericMethod( List<? extends Number> numbers) {
		int total = 0;
		for(Number number : numbers  ) {
			total += number.intValue();
		}
		System.out.println("컬렉션에 저장 된 요소의 총합:"+total);
	}/////////nonGenericMethod
	
	 //위 메소드를 제너릭 메소드로 변환!!!!!	list<T>의 는 맨 위(MYGENERIC)의 T임
//	public static <? extends Number> void GenericMethod(List<T> numbers) {}
	                                //list<T>의 는 맨 위(MYGENERIC)의 T임
	//?를 T로 해야   맨 위(MYGENERIC)의 T가 아닌 <T>반환타입형태의 T로 컴파일 
	public static <T extends Number> void GenericMethod(List<T> numbers) {
		int total = 0;
		for(Number number : numbers  ) {
			total += number.intValue();
		}
		System.out.println("컬렉션에 저장 된 요소의 총합:"+total);
	}//////////GenericMethod
	
}

얘는 클래스와 메소드

public class GenericApp {

	public static void main(String[] args) {
		System.out.println("[타입 파라미터 미지정]");
		MyGeneric generic1 = new MyGeneric();
		generic1.setField("NON TYPE-PARAMETER");   // OBJECT
		String value = (String)generic1.getField();
		System.out.println("저장된 문자열의 길이:"+value.length());
		
		System.out.println("[타입 파라미터 지정]");
		MyGeneric<Student> generic2 = new MyGeneric<>();
	//	generic2.setField("TYPE-PARAMETER"); 컴파일시 타입체크 Student 만 가능
		generic2.setField(new Student("가길동",20,"2022학번"));///setField(Student)
		generic2.getField().print();
		
		System.out.println("[제너릭 메소드 호출: 정적메소드 - 타입 파라미터 지정]");
		// 클래스명.<integer>메소드명()- 인자로 integer 타입 배열만 가능
		//반환타입 무조건 integer
		System.out.println( MyGeneric.<Integer>getEndValue1(1,2,3,4,5));
//		System.out.println( MyGeneric.<Integer>getEndValue1(1,2,3,4.5,5));
		
		System.out.println("[제너릭 메소드 호출: 정적메소드 - 타입 파라미터 미지정]");
		System.out.println( MyGeneric.getEndValue1(1,2,3,4.5,5));
		System.out.println( MyGeneric.getEndValue1(new String[] {"한라산","덕유산","소백산"}));
		
		System.out.println("[제너릭 메소드 호출: 인스턴스 메소드 - 타입 파라미터 지정]");
		System.out.println(generic2.<String>getEndValue2("도봉산","북한산","관악산"));
		System.out.println("[제너릭 메소드 호출: 인스턴스 메소드 - 타입 파라미터 미지정]");
		System.out.println(generic2.getEndValue2(1,2,3,4.5,5));
		
		System.out.println("[타입 파라미터 제한하기:non 제너릭 메소드]");
		List<Character> list1 = Arrays.asList('가','나','다','라');
//		MyGeneric.nonGenericMethod(list1); 타입체크가 됨 number만 들어가야지....
		MyGeneric.nonGenericMethod(Arrays.asList(1,2,3.14,4));		
		System.out.println("[타입 파라미터 제한하기:제너릭 메소드]");
	//	MyGeneric.GenericMethod(list1); 타입체크함
		MyGeneric.GenericMethod(Arrays.asList(1,2,3.14,4));  
		
		
	}////m
}///////////c

 

얜 걍 보면 이해 할 수 있을 정도까지만 하쟈..

'학원 > JDBC' 카테고리의 다른 글

10/25 28-7 lambda  (1) 2022.10.25
10/25 28-6 람다식 과 Stream 이론 정리  (1) 2022.10.25
10/25 28-4 제너릭(Generic) 이론정리  (0) 2022.10.25
10/25 28-3 TransationSQL(트랜젝션처리)  (1) 2022.10.25
10/25 28-2 ExecuteSQL  (1) 2022.10.25

제너릭(Generic)

어려워서 뭔말인지 하.나.도 모르겠음 멘붕멘붕멘붕

다행히도 선생님이 이거 어려워서 이해 못해도 괜찮다고 하셨는데 ... 절대 안 괜찮을 거 같아서 걍 교안내용이라도 퍼 와야 겠음..... 근데 아직도 멘붕멘붕

 

클래스메소드 사용 시 타입을 지정할 수 있도록 하는 일반(Generic)화된 타입이라는 의미 

아!!!! 제너릭은 클래스나 메소드 애들이랑 관련 되어있는 거군 !!

풀어서 설명하자면 클래스나 메소드에서 사용할 데이터 타입을 클래스 정의할 때 결정하는 것이 아니라 인스턴스를 생성할 때나 메소드를 호출할 때 결정하는 기법이다   

더 풀어서 설명하면 아예 처음부터 타입을 결정해 놓는게 아니고 실제로 사용 할 때 타입이 결정된다는 그런 말! 

   ex) List  ==> 지정안하면 모든 타입 입력 가능

         List<타입지정>   => 지정된 타입만 입력가능

 

제너릭은 왜 써요?
제너릭은 사용 시 타입을 지정하기 때문에 컴파일시 타입 체크를 해주는 기능(Type Safety)를 통해 런타임에러를 사전에 방지할 수 있다. 
JDK1.7부터 클래스를 인스턴스화 할 때 new 클래스명<파라미터 타입>()의  '파라미터 타입'을 생략할 수 있다.
즉, new 클래스명<>()로 인스턴스화 할 수 있다     

ex) List<student> = new ArrayList<>(); 이게 가능했던 이유다!!!!!

정리하면

-컴파일시 타입 체크 ok
-형변환 안해도 ok
-코드의 중복 제거 ok

 

제너릭 타입
타입을 파라미터로 가지는 클래스(제너릭 클래스)와 인터페이스(제너릭 인터페이스)들을  제너릭 타입이라 한다.(즉 Integer 타입,String타입이 아닌 일.반.화.된. 타입이다! 말이 일반화지 아무거나 가 더 이해하기 쉬울 듯?) 
 타입 파라미터는 일반적으로 대문자 알파벳 한 글자(T) 로 보통 표현한다 
 제네릭 타입은 두 개 이상의 멀티 파라미터를 이용할 수 있다. 이 때 각 타입 파라미터는 콤마로 구분한다.  Map<K,V>
타입 파라미터는 static 이 붙는 정적 멤버변수 나 정적 메소드, new로 초기화하는 인스턴스 멤버 변수에는 사용할 수 없다

 ****단,제너릭 메소드에는 static을 붙일 수 있다

주의할 것이 제너릭 메소드랑 클래스랑은  관계가 무관함 !!!!

 

ex)

 public class A <T> { 
              T num ;
             }
new A <integer> ( ) 요렇게 생성하면  num 도 integer로 사용된다!
T num = new T(); 이건 노노노노노노

 

제너릭을 사용한 경우 예시 
public class Generic <T> {
           private T field;
           private T newField=new T();

                               // class인스턴스화 할 때 결정되는데, 지금은 타입이 결정 되지 않아서 heap에 메모리 생성 불가
           public static T staticField;  마찬가지 타입이 결정되지 않아서 클래스 로드시점에 메모리 생성불가
           public void add(T field){      //제너릭 메소드가 아님 인스턴스형 메소드 => static 못 붙임
                        this.field=field;
                           }
           public T get(){                        //얘도 제너릭 메소드가 아님
                         return field;
                           } 
          public <T> T genericMethod(T param){    <T>이 의미는 T는 타입파라미터야 라는 정보를 알려 줌
                         return param;
                           }                   // 얘는 제너릭 메소드 이때 T는 Generic의  T와 무관하다   => static 붙일 수 있음
           public static <E> E genericStaticMethod(E param){    E는 타입파라미터야 라는 정보랑 같이 로드..
                          return param;     // 얘도 제너릭 메소드 이 때도 E는 Generic의  T와 무관하다
                             }
      }
  

제너릭 메소드(Generic Method)   => 위에서 보듯 클래스랑 아무런 상관 없음

non제너릭클래스에 제너릭 메소드 사용 가능!
클래스에 "타입 파라미터를 선언하지 않고"  "메소드마다" 타입 파라미터를 선언 해 사용할 수 있다.
즉, 제너릭 클래스(제너릭 타입)가 아니어도 해당 클래스안에 제너릭 메소드를 만들 수 있다
제너릭 메소드는 반환타입 이전에 <>로 타입 파라미터를 선언하고, 제너릭 클래스의 타입 파라미터와는 무관하다

ex)  2여기에 string 들어옴
      public <T> T genericMethod(T param){   
                  return param;
                          }     => T 여기에 String 이 들어오면 T 여기도 String이 들어옴

   ++ 컴파일러가 인자의 타입을 보고 반환 타입을 "추정"할 수 있다

                  String value = 인스턴스변수.genericMethod<String>("문자열");
                                             string 생략 가능 뒤에 "문자열"로 string을 추정 함

 

제너릭 메소드 호출
방법1.
 클래스명(static이 붙은경우).<자료형>메소드명(데이타)
 혹은 인스턴스변수.<자료형>메소드명(데이타)
:타입에 맞는 데이타만 전달할 수 있다
방법2.
 클래스명(static이 붙은경우).<자료형>메소드명(데이타)
 혹은 인스턴스변수.<자료형>메소드명(데이타)
:데이타의 타입을 보고 컴파일러가 타입을 추정한다

 

앤 여기서 .... 끝내야겠어 .... 더 이상 뭔소린지 모르겠다.... 안녕 제너릭 

 

 

 

오라클에서 개념 배웠던 트랜젝션 (그 !! 은행업무에서 많이 쓴다고 했던 거 일련의 작업을 하나로 묶어서 성공하면 저장, 실패하면 롤백 하는 거 !) 을 자바에서도 구현 할거임

 

[트랜잭션 처리]

1) Connection 개체의 setAutoCommit(false)를 이용 자동 commit 막기: 

   디폴트가 commit이라서 자동커밋을 막으려면 false로 설정 해 줘야 한다.

   단, false로 설정하더라도 Connection 개체 close()시 자동 commit 된다 즉, close()를 안하면 commit이 안되는거고
    setAutoCommit(true)인 경우 close()를 안하더라도 자동 commit된다.
2) catch 절에서 con.rollback();
3) try절의 마지막에서 con.commit();

 

public class TransationSQL extends IConnectImpl {

	public TransationSQL(){
    	connect(ORACLE_URL,"KOSMO","KOSMO");
    }
	
    @Override
	public void execute() throws Exception {
     try{
            conn.setAutoCommit(false);  // 자동커밋 방지
            String sql = "DELETE member WHERE username=?";
              // 첫 번째 쿼리문
            psmt = conn.prepareStatement(sql);  // 객체생성
            psmt.setString(1,getValue("삭제할 아이디"));
                System.out.println(psmt.executeUpdate()+"행이 삭제되었습니다.");

              // 두 번째 쿼리문
              sql = "INSERT INTO member VALUES(?,?,?,SYSDATE)";
              psmt = conn.prepareStatement(sql);
              psmt.setString(1,getValue("아이디"));
              psmt.setString(2,getValue("비밀번호"));
              psmt.setString(3,getValue("이름"));
                System.out.println(psmt.executeUpdate()+"행이 입력 되었습니다.");
              conn.commit();
                System.out.println("커밋되었습니다.");
     }
     catch(SQLException e){
     		  conn.rollback();
                System.out.println("롤백되었습니다.");		           
     }
     finally{ //작업 실패 해도 커밋전에 롤백되는게 먼저 실행 되니 finally절에서 닫아주면 된다!
     	close();
     }
    }


public static void main(String[] args) throws Exception {
		new TransationSQL().execute();
	}
}

롤백되어 첫번째 두번재 쿼리문 모두 롤백 됨

'학원 > JDBC' 카테고리의 다른 글

10/25 28-5 Generic 코딩으로 알아보기  (0) 2022.10.25
10/25 28-4 제너릭(Generic) 이론정리  (0) 2022.10.25
10/25 28-2 ExecuteSQL  (1) 2022.10.25
10/25 28-1 ResultSetMetaData (인터페이스)  (0) 2022.10.25
10/24 27-15 (ResultSetType)  (0) 2022.10.24

이제 어떠한 문도 상관없이 다 가능하게 하겠숴 !!!

 

다시 한번 중요 내용 정리정리

 

execute()는 쿼리문이 SELECT이면 true,그외 SQL문일때는 false반환.
execute()메소드로 쿼리 실행 후 쿼리문이 SELECT이면

   => ResultSet에 담긴 결과 출력, Statement계열 객체의 getResultSet()메소드로 호출
쿼리문이 INSERT/DELETE/UPDATE 이면
   =>영향받은 행의 수 출력, getUpdateCount()메소드 호출



 

 

public class ExecuteSQL extends IConnectImpl {
	public ExecuteSQL(String url,String user,String password) {
    	super(url,user,password);	
    }
    
    @Override
	public void execute() throws Exception {
    while(true){
            String sql = getQuerySstring();  //쿼리문 준비
            if("exit".equalsIgnoreCase(sql)){
                System.out.println("종료합니다.");
                close();
                System.exit(0);
            }
            psmt = conn.prepareStatement(sql);  // 객체생성  

            //사용자가 어떤 문을 불러올지 몰라서 execute로 쿼리실행! select만 true/나머지는 false반환
          try{
                boolean flag = psmt.execute();
                if(flag){   //select문 일 때 출력할 코드
                    rs=psmt.getResultSet();
                    ResultSetMetaData rsmd = rs.getMetaData();
                    List<Integer> dashCount = new Vector<>();
                    int columnCount = rsmd.getColumnCount();
                        for(int i=1 ; i<= columnCount ; i++){
                            int columnType = rsmd.getColumnType(i);
                            int columnSize = rsmd.getPrecision(i);
                            switch(columnType){
                                case Types.NCHAR:
                                case Types.NVARCHAR:
                                    dashCount.add(columnSize*2); break;	
                                case Types.NUMERIC:
                                case Types.TIMESTAMP:     // DATE 아님!!!!  이건 시분초까지 있음!
                                    dashCount.add(10); break;
                                default :
                                    dashCount.add(columnSize); break;	
                            }///switch
                            String columnName = rsmd.getColumnName(i).length() > dashCount.get(i-1)?
                                                rsmd.getColumnName(i).substring(0,dashCount.get(i-1)) :
                                                rsmd.getColumnName(i);	
                            System.out.print(String.format("%-"+(dashCount.get(i-1)+1)+"s",columnName));                    
                        }////for
                            System.out.println(); // 줄바꿈
                            for(Integer count : dashCount) {   // dash 출력용
                                for(int i=0 ; i < count ; i++) System.out.print("-");
                                System.out.print(" ");					
                            }///for
                            System.out.println(); // 줄바꿈
                            //데이터 출력하기
                            while(rs.next()){
                                for(int i=1 ; i<= columnCount ; i++ ){
                                    int columnType = rsmd.getColumnType(i);
                                    String columValue;
                                    if(columnType == Types.TIMSTAMP)    //날짜 형식만 더 체크
                                        columValue = rs.getDate(i).toString();
                                    else
                                        columValue = rs.getString(i);
                                    System.out.print(String.format("%-"+(dashCount.get(i-1)+1)+"s",
                                                                                columValue==null? "" : columValue));   
                                }///for
                                 System.out.println(); // 줄바꿈
                            }///while

                }//// if
                else{   // 나머지 일 때 출력할 코드  수행한 행의 수는 getUpdateCount()로 호출
                    int affected = psmt.getUpdateCount();
                    if(sql.trim().toUpperCase().startsWith("UPDATE"))
                        System.out.println(affected+"행이 수정되었습니다.");
                    else if (sql.trim().toUpperCase().startsWith("DELETE"))
                        System.out.println(affected+"행이 삭제되었습니다.");
                    else if (sql.trim().toUpperCase().startsWith("INSERT"))
                        System.out.println(affected+"행이 입력되었습니다.");                
                }
          }////try 밖
          catch(SQLException e){
             System.out.println(e.getMessage());
          }
    }///while 밖
   }////execute
                   
    public static void main(String[] args) throws Exception {
	  new ExecuteSQL(ORACLE_URL,"KOSMO","KOSMO").execute(); 	  

	}///m
}////c

MetaData?? 

어떤 데이터에대한 데이터 ...

컬럼명 같은 거 어떤집합으로 묶여있는지에 대한 정보?

예를들어 

20 160 45
30 170 50
40 178 60
나이 몸무게
20 160 45
30 170 50
40 178 60

이렇게 숫자만 들어있는 표만 보면 이게 뭔지 알 수 없잖아??

근데 위에 행 하나만 추가하면 뭔지 알 수 있게 됨!! 저 맨 위에 추가한 행을 MetaData라고 함!

 

[특징]

ResultSetMetaData인터페이스를 통해 얻어 올 수 있다.
ResultSetMetaData인터페이스는 ResultSet 개체의 getMetaData()메서드로 얻어 올 수 있다.
-ResultSetMetaData는 컬럼명,컬럼의 null여부, 컬럼 타입 등 컬럼에 대한 정보를 가지고 있다.

 

[ResultSetMetaData의 주요 메서드]  => SELECT문 입력 시 주로 사용!

int getColumnCount():컬럼의 개수 얻어 온다.
String getColumnName(int column)  :컬럼의 이름을 얻어 온다. (column에는 인덱스 값을 준다)
int getColumnType(int column)   : 타입인데 숫자로 반환? 상수로 설정 되어 있음
String getColumnTypeName(int column)  : 컬럼의 타입을 얻어 온다.
int isNullable(int column)  : 컬럼의 null허용여부, ex) null허용 = 1, not null =0 

ex) 컬럼 개수 얻어오기

ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM emp");
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();

 

[SELECT쿼리 실행시 컬럼에 대한 정보 얻기] 흐름 보기**

1.ResultSet객체의 getMetaData()로 ResultSetMetaData얻기

2.총 컬럼수 얻기-ResultSetMetaData의 int getColumnCount()

3.컬럼명 얻기-ResultSetMetaData의 String getColumnName(int column)

4.컬럼타입 얻기-int getColumnType(int column) :타입과 관련된 상수는 java.sql.Types클래스에 정의됨.

5.오라클의 타입명으로 반환  String getColumnTypeName(int column)

        6.컬럼의 NULL허용여부 :int isNullable(int column) : NULL허용 :1,NOT NULL:0

        7.컬럼의 크기 얻기 : getPrecision(int column)

 

[각 컬럼의 자리수 설정하기]
  오라클처럼  NUMBER타입(자리수 지정 안한 NUMBER포함)은 10자리
 DATE타입은 10자리(원래 오라클은 8자리) CHAR게열(VARCHAR2)는 해당 자리수로 설정하는데
 (단 NCHAR계열은 자리수의 2배로 설정)
 오라클 처럼 컬럼명 밑에  ---------  를 표시하기위한 작업

 

++하기 전 저번에 만들었던 IConnectlmpl 부모클래스에서 마지막 getQueryString() 메소드 구현 안했는데

이거 하기 전에 바꿔놓아야 함!

 

 

 

@Override
	public String getQueryString() {	
		System.out.print("SQL>");
		return sc.nextLine();
	}//////
public class ResultSetMetadataSQL extends IConnectImpl {
	//기본생성자로 연결
    public ResultSetMetadataSQL() {
			connect(ORACLE_URL,"scott","scott");
	}
    
    @Override
	public void execute() throws Exception {
    	   // 쿼리문 준비
    	  String sql = getQueryString();
           // preparedStatement 객체 생성
          psmt = conn.preparedStatement(sql);
           // 쿼리 실행! 끝에 ; 이거 입력하면 안됨!
          rs = psmt.executeQuery();
           //select 실행 시 컬럼 정보 얻기 metadata로 가져오기
          ResultSetMetaData rsmd = rs.getMetaData();
           // 컬럼 수 얻기
          int columnCount = rsmd.getColumnCount();
            System.out.println("총 컬럼 수:"+columnCount);
           // 컬럼명 얻기
          for(int i=1 ; i <= columnCount ; i++) {
				String columnName = rsmd.getColumnName(i);
				int length = columnName.length()+2;  //   2칸여백 줌
				System.out.print(String.format("%-"+length+"s", columnName));
		   }
           // 컬럼 타입 얻기 int getColumntype(int column)사용, types클래스에 정의됨.
                System.out.println("\r\n[자바의 컬럼타입으로 얻기]");
			   for(int i=1 ; i<= columnCount ; i++) {
                    int columnType = rsmd.getColumnType(i);
                    switch(columnType) {
                        case Types.VARCHAR: 
                            System.out.println("오라클의 VARCHAR2"); break;
                        case Types.NVARCHAR:
                            System.out.println("오라클의 NVARCHAR2");break;
                        case Types.CHAR:
                            System.out.println("오라클의 CHAR");break;
                        case Types.NCHAR:
                            System.out.println("오라클의 NCHAR");break;
                        case Types.NUMERIC:
                            System.out.println("오라클의 NUMBER");break;
                        case Types.TIMESTAMP:  // DATE 아님!!!!  이건 시분초까지 있음!
                            System.out.println("오라클의 DATE");break;	
                        default :
                            System.out.println("오라클 기타 자료형");										
				}				
			}  
           //컬럼타입 이름 getColumnTypeName 사용
	 	  System.out.println("[오라클의 컬럼타입으로 얻기]");
			for(int i=1 ; i<= columnCount ; i++) {
				String columnTypeName=rsmd.getColumnTypeName(i);
				System.out.println(columnTypeName);				
			}
		   //null 허용여부 isNullable 사용
		  System.out.println("[컬럼의 널 허용여부 얻기]");
			for(int i=1 ; i<= columnCount ; i++) {
				int isNull = rsmd.isNullable(i);
				System.out.println(isNull == 1 ? "NULL 허용" : "NOT NULL");
			}
		   //컬럼크기 얻기, 괄호 없는 건 0반환 getPrecision 사용
		  System.out.println("[컬럼의 크기 얻기]");
			for(int i=1 ; i<= columnCount ; i++) {
				int columnSize = rsmd.getPrecision(i);
				System.out.println(columnSize);      // 소수점이하 자리는 안나옴
			}	
            
           // 각 컬럼 자리 수 설정하기 오라클처럼 출력!!
			List<Integer> dashCount = new Vector<>();
			
			for(int i=1 ; i<= columnCount ; i++) {
				int columnType = rsmd.getColumnType(i);
				int columnSize = rsmd.getPrecision(i);
				switch(columnType) {				 
					case Types.NCHAR:
					case Types.NVARCHAR:
						dashCount.add(columnSize*2); break;	
					case Types.NUMERIC:
					case Types.TIMESTAMP: // DATE 아님!!!!  이건 시분초까지 있음!
						dashCount.add(10); break;
					default :
						dashCount.add(columnSize); break;								
			   }////swich
               //컬럼명 출력
               //컬럼명의 길이가 대쉬의 숫자(자료형크기)보다 크다면
               //ex) GENDER CHAR(1) 
               //   G
               //   -
               
				String columnName = rsmd.getColumnName(i).length() > dashCount.get(i-1) ? 
									rsmd.getColumnName(i).substring(0,dashCount.get(i-1)) :
									rsmd.getColumnName(i);				
				System.out.print(String.format("%-"+(dashCount.get(i-1)+1)+"s",columnName));				
			}///for
				System.out.println();  // 줄바꿈
				//dash출력
				for(Integer count : dashCount) {
					for(int i=0 ; i < count ; i++) System.out.print("-");
					System.out.print(" ");					
				 }///for
				System.out.println();// 줄바꿈
				// 데이터 출력
				while(rs.next()) {
					// 컬럼값 뽑기
					for(int i=1 ; i<= columnCount ; i++) {
						int columnType = rsmd.getColumnType(i);
						String columValue;
						if(columnType == Types.TIMESTAMP)  // 날짜만 타입 체크
							columValue = rs.getDate(i).toString();
						else
							columValue = rs.getString(i);
						System.out.print(String.format("%-"+(dashCount.get(i-1)+1)+"s",
													columValue==null? "" : columValue));
					}//for
					System.out.println();    // 줄바꿈
				}///while									
		}		
		finally {
		     close();
		}
          
    }
    

public static void main(String[] args) throws Exception {
		new ResultSetMetadataSQL().execute();
		
	}
}

 

이름 컬럼만 출력 해봄

 

'학원 > JDBC' 카테고리의 다른 글

10/25 28-3 TransationSQL(트랜젝션처리)  (1) 2022.10.25
10/25 28-2 ExecuteSQL  (1) 2022.10.25
10/24 27-15 (ResultSetType)  (0) 2022.10.24
10/24 27-14 (IsmemberProc().CallableStatement)  (0) 2022.10.24
10/24 27-13 (DeleteProc.CallableStatement)  (0) 2022.10.24

 [ResultSet 개체의 주요 메서드]


-next():다음행으로 커서를 옮김
-previous():이전 행으로 커서를 옮김
-first():첫번째 행으로 커서를 옮김
-last()마지막 행으로 커서를 옮김
-afterLast():커서를 마지막 행 바로 다음으로 옮김(EOF:END OF FILE)
-beforeFirst():커서를 첫번째 행 바로 앞으로 옮김(BOF:BEGIN OF FILE)
-getRow():현재 커서가 위한 행의 인덱스를 돌려 준다.인덱스는 첫번째 행 바로 앞이 0
-absolute(인덱스): 해당 인덱스 로 커서 이동, 양수-전진 ,음수-후진

public class ResultSetType extends IConnectImpl{
	public ResultSetType(String url, String user, String password){
            super(url,user,password);
    }

	@Override
	public void execute() throws Exception {
         try{
                   //1.쿼리문 미리 준비
                String sql = "SELECT *FROM emp ORDER BY sal DESC";
                  //2.쿼리 실행용 객체 (Statement계열-PreparedStatement) 생성
                  //psmt = conn.prepareStatement(sql);	   이건 전진만 가능 함
                  //전, 후진 가능모드 인자들 잘 확인하자!
                psmt = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
                rs = psmt.executeQuery();
                  //3.쿼리 실행
                System.out.println("커서를 마지막 레코드 이동:"+rs.last());
                System.out.println("총 레코드 수:"+rs.getRow());
                System.out.println("[연봉이 높은 순]");
                rs.beforeFirst();    // 커서를 위로 올려서!!
                while(rs.next()) {   // 내려오면서 실행 됨
                            System.out.println(String.format("%-6s%-8s%-11s%-6s%s",
                                    rs.getString(1),
                                    rs.getString(2),
                                    rs.getString(3),
                                    rs.getString(6),
                                    rs.getDate(5)
                                    ));
                        }						// 커서 내려 와있으니
                 System.out.println("[연봉이 낮은 순]");
                 while(rs.previous()) {         // 올라가면서 실행, 출력!
                            System.out.println(String.format("%-6s%-8s%-11s%-6s%s",
                                    rs.getString(1),
                                    rs.getString(2),
                                    rs.getString(3),
                                    rs.getString(6),
                                    rs.getDate(5)
                                    ));
                        }							                
            } 
        finally {
		   close();
		    }
   }

public static void main(String[] args) throws Exception {	
		new ResultSetType(ORACLE_URL,"scott","scott").execute();
		
	}//////main
}/////class

회원인지 아닌지 구분하는 오라클 함수

 

CREATE OR REPLACE PROCEDURE SP_ISMEMBER
(
id  member.username%TYPE,
pass  member.password%TYPE,
rtval OUT NUMBER
)
IS
flag NUMBER(1);
BEGIN
SELECT COUNT(*) INTO flag FROM member 
WHERE username = id;

IF flag = 0 THEN  --아이디 존재하지 않은 경우
rtval := -1;
ELSE --아이디 존재
SELECT COUNT(*) INTO flag FROM member 
WHERE username = id AND password = pass;
IF flag = 0 THEN --비번 불일치
rtval := 0;
ELSE --회원
rtval := 1;
END IF;
END IF;
END;

 

얘도 아웃파라미터에 해당하는 값들이 숫자이다보니

결과를 쉽게 알 수있는 문자로 바꿔줘야 겠지? 그럼 switch문 을 또 쓰겠네

 

public class IsmemberProc extends IConnectImpl {
	
    public IsmemberProc() {
		connect(ORACLE_URL,"KOSMO","KOSMO");		
	}
    
    @Override
	public void execute() throws Exception {
    	csmt = conn.prepareCall("{call SP_ISMEMBER (?,?,?)}");
		//인파라
		String user = getValue("검색 할 아이디");
		csmt.setString(1,user);
		csmt.setString(2,getValue("비밀번호"));
        //아웃 파라
		csmt.registerOutParameter(3,Types.NUMERIC);
		csmt.execute();
        int rtNum =csmt.getInt(3);
		switch(rtNum) {
			case -1 : System.out.println("아이디 없음"); break;
			case 0 : System.out.println("아이디 존재 비번 불일치 "); break;
			default : System.out.println(user+"님 hi");
		}        
    	close();
    }
    
    
public static void main(String[] args) throws Exception {
		 new IsmemberProc().execute();

	}
}

+ Recent posts