본문 바로가기
Programming Language/Java

[국비] Java 내용정리 Day19

by tpleehan 2021. 12. 2.

익명객체

  • 구현 클래스가 매번 달라지거나, 한 번만 사용되는 경우 구현 클래스를 생성하지 않고 익명 클래스(이름이 없는 클래스)로 선언할 수 있다.

package anonymous.basic;

interface Car {
	public void run(); // 추상 메서드
}

class Sonata implements Car {

	@Override
	public void run() {
		System.out.println("소나타가 달립니다.");
	}
	
}

public class Garage {

//	public Car car = new Sonata(); 일반적인 인터페이스 구현 객체 사용법
	
	public Car car = new Car() {
		public void run() {
			System.out.println("익명객체가 달립니다.");
		}
	};
	
	public Garage() {
		car.run();
	}
	
}
package anonymous.basic;

public class MainClass {

	public static void main(String[] args) {
		
		Car s1 = new Sonata();
		s1.run();
		
		Car s2 = new Sonata();
		s2.run();
		
//		Garage g = new Garage();
		
		Car tesla = new Car() {
			@Override
			public void run() {
				System.out.println("테슬라가 달립니다.");
			}			
		};
		
		tesla.run();
		
		new Car() {
			@Override
			public void run() {
				System.out.println("포르쉐는 쌩쌩 달립니다.");
			}			
		}.run();
		
	}

}
package anonymous.basic2;

public interface RemoteController {
	void turnOn();
	void turnOff();
	void volumeUp();
	void volumeDown();	
}
package anonymous.basic2;

public class Tv implements RemoteController{

	private int volume;
	
	@Override
	public void turnOn() {
		System.out.println("Tv를 켭니다.");
	}

	@Override
	public void turnOff() {
		System.out.println("Tv를 끕니다.");		
	}

	@Override
	public void volumeUp() {
		 volume++;
		 System.out.println("Tv의 볼륨: " + volume);
	}

	@Override
	public void volumeDown() {
		volume--;
		System.out.println("Tv의 볼륨: " + volume);		
	}
	
}
package anonymous.basic2;

public class Radio {

	private int sound;
	private RemoteController remote;
	
	public Radio() {
		remote = new RemoteController() {
			
			@Override
			public void volumeUp() {
				sound++;
				System.out.println("라디오의 볼륨: " + sound);
			}
			
			@Override
			public void volumeDown() {
				sound--;
				System.out.println("라디오의 볼륨: " + sound);				
			}
			
			@Override
			public void turnOn() {
				System.out.println("라디오를 켭니다.");				
			}
			
			@Override
			public void turnOff() {
				System.out.println("라디오를 끕니다.");
			}
		};
	}
	
	public RemoteController getRemote() {
		return remote;
	}
	
	public void setRemote(RemoteController remote) {
		this.remote = remote;
	}
	
}
package anonymous.basic2;

public class MainClass {

	public static void main(String[] args) {
		Tv tv = new Tv();
		tv.turnOn();
		tv.turnOff();
		tv.volumeUp();
		tv.volumeDown();
		
		//////////////////////////////////////
		
		Radio radio = new Radio();
		radio.getRemote().turnOn();
		radio.getRemote().turnOff();
		radio.getRemote().volumeUp();
		radio.getRemote().volumeDown();
	}

}

람다식(Lambda Expression)

  • 함수적 프로그래밍
  • Y = f(x); 형태의 함수로 구성된 프로그래밍 기법
  • 함수를 매개 값으로 전달하고 결과를 받는 코드로 구성

함수적 프로그래밍이 객체 지향 프로그래밍 보다는 효율적인 경우

  1. 대용량 데이터의 처리시
  2. 이벤트 지향 프로그램시

Java 8부터 함수적 프로그래밍을 지원한다.

  • 람다식(Lambda Expression)를 제공한다.
  • 익명 함수를 생성하기 위한 식
    • (매개변수, 매개변수) -> { 실행문 }

람다식의 장점

  • 코드가 간결해 진다.
  • 컬렉션 요소 처리가 쉬워진다.

람다식의 기본 사용

  • 자바의 람다식은 함수적 인터페이스의 익명 구현 객체를 대신한다.
  • 람다식(Lambda Expression)은 코드블럭(code block)을 메소드에 넣을 때 사용하는 기술이다.
package lambda.basic;

//함수적 인터페이스 -> 구현해야 하는 추상 메서드가 1개인 인터페이스
public interface Say01 {
	void talking();	
}
package lambda.basic;

public interface Say02 {
	String talking();	
}
package lambda.basic;

public interface Say03 {
	String talking(String greet);	
}
package lambda.basic;

public interface Say04 {
	String talking(String word, int i);	
}
package lambda.basic;

public class Person {

	public void greet(Say01 say) {
		say.talking();
	}

	public void greet(Say02 say) {
		say.talking();
	}
	
	public void greet(Say03 say) {
		say.talking("안녕하세요");
	}
	
	public String greet(Say04 say) {
		String result = say.talking("반갑습니다.", 3);
		return result;
	}

}
package lambda.basic;

interface Calculator {
	int add(int n1, int n2);
}

public class MainClass {

	public static void main(String[] args) {
		
		Person p = new Person();
		
		p.greet(new Say01() {
			@Override
			public void talking() {
				System.out.println("안녕하세요.");
			}			
		});
		
		p.greet(new Say02() {
			@Override
			public String talking() {
				System.out.println("Hello");
				return "Hello";
			}			
		});
		
		p.greet(new Say03() {
			@Override
			public String talking(String greet) {
				System.out.println(greet);
				return greet;
			}			
		});
		
		String say04test = p.greet(new Say04() {
			@Override
			public String talking(String word, int i) {				
				String result = "";
				for (int j = 1; j <= i; j++) {
					result += word;
				}
				return result;
			}			
		});
        
		System.out.println("Say04 기본 메서드 호출: " + say04test);
		
		System.out.println("------------------------------------");
		
		p.greet(() -> {
			System.out.println("안녕하세요.");
		});
		
		p.greet((greet) -> {
			System.out.println();
			return greet;
		});

		String str = p.greet((word, i) -> {			
			String result = "";
			for (int j = 1; j <= i; j++) {
				result += word;
			}
			return result;			
		});
		System.out.println(str);
		
		System.out.println("------------------------------------");
		
		// 계산기 인터페이스와 람다식
		Calculator sharp = new Calculator() {			
			@Override
			public int add(int n1, int n2) {
				System.out.println("샤프 계산기의 덧셈");
				return n1 + n2;
			}
		};
		
		System.out.println(sharp.add(10, 15));
		
		Calculator casio = (x, y) -> {
			System.out.println("카시오 계산기의 덧셈");
			return x + y;
		};
		System.out.println(casio.add(100, 200));
		
		// 만약 오버라이딩 하는 추상메서드에 작성할 코드가 한 줄이면 괄호 생략이 가능하다.
		Calculator xiaomi = (x, y) -> x + y;
		System.out.println(xiaomi.add(30, 50));		
	}

}

람다식을 적용하기 위한 스트림

반복자 스트림이란?

  • Java 8부터 추가된 컬렉션의 저장 요소를 하나씩 참조하도록 도와주는 반복자이다.
  • 람다식으로 처리할 수 있도록 해주는 반복자로 파일 입출력 stream과는 다른 개념이다.

스트림의 특징

  • Iterator와 비슷한 역할을 하는 반복자로 대부분 메서드는 함수적 인터페이스 타입이라 속도면에서 빠르다.

package lambda.stream;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class MainClass01 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		
		list.add("홍길동");
		list.add("김철수");
		list.add("박영희");
		list.add("김뽀삐");
		list.add("최또띠");
		
		Iterator<String> iter = list.iterator();
		
		while (iter.hasNext()) {
			System.out.println(iter.next());
		}
		
		System.out.println("---------------------------------");
		
		/*
		Stream<String> stream = list.stream();
		stream.forEach(new Consumer<String>() {
			@Override
			public void accept(String t) {
				System.out.println(t);
			}
			
		});
		 */
		list.stream().forEach((s) -> System.out.println(s));		
	}

}
package lambda.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class MainClass02 {

	public static void main(String[] args) {

		List<Integer> list = new ArrayList<>();
		
		for (int i = 1; i <= 100; i++) {
			list.add((int) (Math.random() * 100) + 1);
		}
		
		System.out.println(list);
		
		System.out.println("------------------------------");

		// distinct(): 중복제거
		list.stream()
			.distinct()
			.forEach((num) -> System.out.print(num + " "));
			
		System.out.println("\n------------------------------");
		
		// filter(): 걸러내는 기능
		Stream<Integer> s1 = list.stream()
								 .filter((num) -> num % 2 == 0);
								// 작성한 조건식의 결과가 true면 리턴
		s1.forEach((num) -> System.out.print(num + " "));
		
		System.out.println("\n------------------------------");
		
		// sorted(): 정렬
		list.stream()
			.sorted()
			.forEach((num) -> System.out.print(num + " "));
		
		System.out.println("\n------------------------------");
		
		// map(): 메서드 안에 정의된 새로운 stream으로 반환
		Stream<String> s2 = list.stream().map((num) -> {
			return num % 2 == 0 ? "짝수" : "홀수";
		});
		
		s2.forEach((str) -> System.out.print(str + ", "));
		
		System.out.println("\n------------------------------");
		
		// 50보다 크면 값을 반환, 아니면 0을 반환
		list.stream()
			.map((t) -> t > 50 ? t : 0)
			.forEach((t) -> System.out.print(t + " "));
		
		System.out.println("\n------------------------------");
		
		// 50보다 크면 원본을 반환, 아니면 0을 반환, 0을 제거 후 출력
		list.stream()
			.map((num) -> num > 50 ? num : 0)
			.filter((i) -> i != 0)
			.forEach((j) -> System.out.print(j + " "));		
	}

}

Lambda Stream Quiz

1. BufferedReader를 사용해서 csv파일을 읽어들인다.
2. ,(콤마)를 기준으로 잡아서 분할 한 뒤 Data객체에 한 줄 단위로 저장
3. List<Data>에 추가한다.
4. 람다식을 이용해서 지역: 서울, 월: 짝수 의 분양가격이 4000 이상의 객체만 뽑아서 새로운 list를 생성. (filter)
stream.collect(Collectors.toList()) -> 스트림 객체의 요소를 모아서 새로운 리스트 생성.
5. 새롭게 만들어진 리스트 내부의 내용을 모두 출력
package lambda.stream;

public class Data {

	private String region;
	private String size;
	private String year;
	private String month;
	private String price;
	
	public Data() {		
	}

	public Data(String region, String size, String year, String month, String price) {
		super();
		this.region = region;
		this.size = size;
		this.year = year;
		this.month = month;
		this.price = price;
	}

	public String getRegion() {
		return region;
	}

	public void setRegion(String region) {
		this.region = region;
	}

	public String getSize() {
		return size;
	}

	public void setSize(String size) {
		this.size = size;
	}

	public String getYear() {
		return year;
	}

	public void setYear(String year) {
		this.year = year;
	}

	public String getMonth() {
		return month;
	}

	public void setMonth(String month) {
		this.month = month;
	}

	public String getPrice() {
		return price;
	}

	public void setPrice(String price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return "지역명: " + region + ", 규모구분: " + size + ", 연도: " + year + "년" + " " + month + "월" + ", 분양가격: " + price + "만원";
	}
		
}​
package lambda.stream;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


public class QuizMain {

	public static void main(String[] args) {

//		FileReader fr = null;
		BufferedReader br = null;

		// Data 객체들을 모아놓는 리스트
		List<Data> list = new ArrayList<>();

		FileInputStream fis = null;
		InputStreamReader is = null; // 인코딩을 지정해서 가져올 수 있는 클래스

		try {
			fis = new FileInputStream("C:\\java\\주택도시보증공사_전국 평균 분양가격(2020년 2월).csv");
			is = new InputStreamReader(fis, "EUC-KR");
			br = new BufferedReader(is);

			String str;
			while((str = br.readLine()) != null) {
				
				String[] arr = str.split(",");
//				System.out.println(Arrays.toString(arr));
				String region = arr[0];
				String size = arr[1];
				String year = arr[2];
				String month = arr[3];

				String price;

				try {
					// 공백, - 제거
					arr[4] = arr[4].replace("-", "").replace(" ", "");
					if (arr[4].equals("")) {
						price = "0"; // 없는 값이라면 0을 저장
					} else {
						price = arr[4];
					}					
				} catch (Exception e) {
					price = "0";
				}
				
				Data data = new Data(region, size, year, month, price);
				list.add(data);				
			}
			
			/*
			List<Data> newList =
			list.stream().filter((data) -> data.getRegion().equals("서울"))
						 .filter((data) -> Integer.parseInt(data.getMonth()) % 2 == 0)
						 .filter((data) -> Integer.parseInt(data.getPrice()) >= 4000)
						 .collect(Collectors.toList());
			 */
			List<Data> newList =
					list.stream().filter((data) ->
							data.getRegion().equals("서울") && 
							Integer.parseInt(data.getMonth()) % 2 == 0 && 
							Integer.parseInt(data.getPrice()) >= 4000)
							.collect(Collectors.toList());
			
			newList.stream().forEach((data) -> System.out.println(data));
			
		} catch (Exception e) {
			e.printStackTrace();			
		} finally {
			try {
				br.close();
				is.close();
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

정규표현식(Regular Expression)

  • 문자열이 정해진 패턴으로 구성되어 있는지 검증해야 할 때 사용한다. (이메일, 전화번호 등)
  • 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어로 지정한 패턴과 일치하는 문자열을 검증할 수 있다.

Pattern 클래스

  • java.util 패키지의 Pattern 클래스의 matcher(), matchers() 메서드를 정규표현식 검증에 이용한다.
  • static 메서드
    • compile(패턴)
      • 정규표현엔진(정규식)을 만들어 낸다.
    • matcher(검증 데이터)
      • 데이터를 비교해서 Matcher 클래스로 반환한다.
    • matchers(패턴, 검증 데이터)
      • 패턴으로 비교하여 boolean 형으로 반환한다.

Matcher 클래스

  • 패턴을 이용하여 대상 문자열을 검색할 때 사용하는 클래스다.
    • find()
      • 해당 정규표현을 찾는다.
    • start()
      • 해당 정규표현의 시작 인덱스를 반환한다.
    • group()
      • 해당 정규표현의 값을 반환한다.
    • end()
      • 해당 정규표현의 끝 인덱스를 반환한다.
package regex.pattern;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexEx01 {

	public static void main(String[] args) {

		String info = "30세/서울시 마포구/02-123-4567/010-2345-6789/kkk@naver.com";
		
		/*
		 * 전화번호 형식 
		 * \\d: 숫자 형식인지 파악 
		 * \\d{3} : 숫자 3개를 찾음 
		 * \\d{3, 4}: 숫자가 3 이상 4 이하를 찾음
		 */
		
		String pattern = "\\d{2,3}-\\d{3,4}-\\d{4}";
		
		// 비교/검증이 가능한 정규표현식을 만들어 내는 메서드
		Pattern p = Pattern.compile(pattern);
		// 데이터를 비교해서 Matcher 클래스로 반환
		Matcher m = p.matcher(info);
		
		/*
		if(m.find()) {
			System.out.println("찾은 인덱스: " + m.start());
			System.out.println("끝 인덱스: " + m.end());
			System.out.println("찾은 값: " + m.group());
		}
		 */
		while(m.find()) {
			System.out.println("찾은 인덱스: " + m.start());
			System.out.println("끝 인덱스: " + m.end());
			System.out.println("찾은 값: " + m.group());
		}
	
		/*
		 * 이메일 형식
		 * \\w: 영문자와 숫자를 찾는다.
		 * \\w+: 영문자와 숫자 여러개
		 */
		String pattern2 = "\\w+@\\w+.\\w+";
		Matcher m2 = Pattern.compile(pattern2).matcher(info);
		
		while(m2.find()) {
			System.out.println("찾은 인덱스: " + m2.start());
			System.out.println("끝 인덱스: " + m2.end());
			System.out.println("찾은 값: " + m2.group());
		}
		
	}

}
package regex.pattern;

import java.util.regex.Pattern;

public class RegexEx02 {

	public static void main(String[] args) {
		
		//[]: 해당 위치의 한 글자에 어떤 문자들이 올 수 있는지 정의
		System.out.println(Pattern.matches("s[lh]eep", "sleep"));
		System.out.println(Pattern.matches("s[lh]eep", "sweep"));
		
		/*
		 * # [] 안에 정의할 수 있는 것
		 * 1. [abc]: a, b, c 중 하나만 허용
		 * 2. [^abc]: a, b, c를 제외한 모두를 허용
		 * 3. [a-z]: a부터 z까지 허용
		 *    [a-zA-Z가-힣]: 영문 소문자, 대문자, 한글을 허용
		 * 4. [0-9]: 숫자만 허용
		 * 5. &&: 교집합 (좌항과 우항 패턴을 모두 만족하는 문자)
		 */
         
        System.out.println(Pattern.matches("s[^1-9]eep", "s0eep"));
		System.out.println(Pattern.matches("s[a-zA-Z]eep", "sLeep"));
		System.out.println(Pattern.matches("s[a-dm-z]eep", "sleep"));
		System.out.println(Pattern.matches("s[a-d&&c-f]eep", "sceep"));
		
		/*
		 * # 해당 패턴이 적용될 문자의 개수를 정의하는 법 (공백은 허용하지 않는다.)
		 * 1. Ex{n}: 앞에 있는 패턴이 n글자 일치해야 한다.
		 * 2. Ex{n,m}: 최소 n글자 최대 m글자가 일치해야 한다.
		 * 3. Ex{n,}: 최소 n글자 일치해야 한다. (최대는 제한이 없다)
		 * 4. Ex?: 0번 혹은 한번
		 * 5. Ex+: 최소 한번 이상
		 * 6. Ex*: 0번 혹은 여러 번
		 */
		
		System.out.println(Pattern.matches("....[\\d]{3}", "abcd123"));
		System.out.println(Pattern.matches("[\\w가-힣]{2,12}", "abcd안녕하세요123456"));
		
		String email = "abc@github.io";
		System.out.println(Pattern.matches("[\\w]+@[a-zA-z0-9]+[.][a-zA-Z]+", email));
		
		/*
		 * Pattern.matches(regex, str)
		 * - 전달한 문자열이 정규표현식과 일치하면 일치하면 true. 일치하지 않으면 false
		 * 
		 * Matcher
		 * - 문자열을 처음부터 끝까지 검사해서 해당 정규표현식과 일치하는 인덱스를 찾을 결과를 가지고 있는 객체
		 */         
	}

}

'Programming Language > Java' 카테고리의 다른 글

[국비] Java 내용정리 Day20  (0) 2021.12.04
[국비] Java 내용정리 Day18  (0) 2021.12.01
[국비] Java 내용정리 Day17  (0) 2021.11.29
[국비] Java 내용정리 Day16  (0) 2021.11.28
[국비] Java 내용정리 Day15  (0) 2021.11.25

댓글