TIL - 20210813

so2·2021년 8월 13일
1
post-thumbnail

오늘 공부한 내용 ✍🏻

✍🏻 이것이 취업을 위한 코딩 테스트다 CHAPTER03 그리디

  • 현재 상황에서 지금 당장 좋은 것만 고르는 방법
  • 일반적인 그리디 알고리즘은 문제를 풀기 위한 최소한의 아이디어를 떠올릴 수 있는 능력을 요구
  • 가장 좋아 보이는 것을 반복적으로 선택해도 최적의 해를 구할 수 있는지 검토 → 그리디는 정당성 분석이 중요 !!
  • 일반적인 상황에서 그리디는 최적의 해를 보장할 수 없을 때가 많다. 하지만 코딩 테스트에서의 그리디 문제는 탐욕법으로 얻은 해가 최적의 해가 되는 상황에서, 이를 추론할 수 있어야 풀리도록 출제된다
  • 거스름돈 문제 (p.87)
    • 화폐의 종류가 K라고 할 때, 소스코드의 시간 복잡도는 O(K)
    • 가장 큰 단위 돈을 거슬러 주는 것이 최적의 해를 보장하는 이유 = 큰 단위가 항상 작은 단위의 배수이므로 작은 단위의 동전들을 종합해 다른 해가 나올 수 없다

✍🏻 자바의 신 32장 Java 8에 추가된 것들은 ?

Optional

  • 선택적으로 객체를 처리
  • null 처리를 보다 간편하게 할 수 있다
public final class Optional<T> extends Object 

// 데이터가 없는 Optional 객체 생성 
Optional<String> emptyString = Optional.empty()
// null 추가 
Optional<String> nullableString = Optional.ofNullable(null);
// 반드시 데이터가 들어갈 수 있는 상황 
Optional<String> commonString = Optional.of("common");
private void getOptionalData(Optional<String> data) 
						throws Exception {
	String defaultValue = "default";
	String result1 = data.get();
	// 값이 없을 경우 기본값을 지정할 수 있다 
	String result2 = data.orElse(defaultValue);
	
	Supplier<String> stringSupplier = new Supplier<String>(){
		@Override
		public String get(){
			return "GodOfJava";
		}
	};
	String result3 = data.orElseGet(stringSupplier);

	Supplier<Exception> exceptionSupplier = 
    					new Supplier<Exception>(){
		@Override
		public  Exception get(){
			return new Exception(); 
		}
	};
	// 데이터가 없을 경우 예외 발생 
	String result4 = data.orElseThrow(exceptionSupplier);
}

Default method

  • 인터페이스에 default()메소드를 구현할 수 있다
  • abstract 클래스의 경우 extends를 사용해야 하지만, default를 사용한 인터페이스는 implements 키워드를 사용해 구현해야 한다
public intetface DefaultStaticInterface{
	String getName();
	int Since();
	default String getEMail(){
		return "name@gmail.com";
	}
}

날짜 관련 클래스들

  • java.time 패키지 참고
    • ZonedDateTime, LocalDate, DayOfWeek ....

병렬 배열 정렬

int[] intValues = new int[10];
Arrays.parallelSort(intValues);
  • 기존에 사용하던 sort()는 단일 쓰레드로 수행되며, parallelSort()는 필요에 따라 여러 개의 쓰레드로 나뉘어 작업이 수행된다

  • 성능 테스트 결과를 보면 5000개 이상부터 parallelSort()의 성능이 sort()보다 더 빨라짐을 알 수 있다.

    따라서, 개수가 많지 않은 배열엔 굳이 parallelSort()를 사용할 필요가 없다

StringJoiner

  • 순차적으로 나열되는 문자열을 처리할 때 사용한다
// 배열의 구성요소 사이에 콤마만 넣고자 할 때 
public void joinStringOnlyComma(){
	String[] stringArray = 
    		new String[]{"StudyHard", "GodOfJava", "Book"};
	StringJoiner joiner = new StringJoiner(",");
	StringJoiner joiner2 = new StringJoiner(",","(",")");
	for(String string:stringArray){
		joiner.add(string);
		joiner2.add(string);
	}
	System.out.println(joiner);
	System.out.println(joiner2);
}

//출력값
StudyHard,GodOfJava,Book
(StudyHard,GodOfJava,Book)

✍🏻 자바의 신 33장 Java 8에 변경된 것들은 ?

Lamda 표현식

  • 인터페이스에 메소드가 하나인 것들만 적용 가능

  • 람다표현식 ↔ 익명 클래스 전환 가능

  • 기본 람다 표현식

    매개 변수 목록 | 화살표 토큰(Arrow Token) | 처리 식

    (int x, int y) → x+y

  • 처리식이 한 줄 이상일 때에는 중괄호로 묶을 수 있다

// 이 어노테이션을 사용하면 
// 인터페이스에는 내용이 없는 하나의 메소드만 선언할 수 있다
@FuncctionalInterface
interface Calculate {
	int operation(int a, int b);
}
Calculate cal = (a, b) -> a+b;

// Runnable은 run()메소드 밖에 없기 때문에 람다 표현식 처리 가능
new Thread(()->{
	System.out.println("람다");
}).start();

or 

new Thread(() -> System.out.println("람다")).start();

java.util.function 패키지

Predicate

  • bolean teat() : 두 객체 비교
  • and(), negate(), or(), inEqual() ...
Predicate<String> predicateLength5 = (a) -> a.length()>5;
Predicate<String> predicateContains = (a) -> a.contains("God");
Predicate<String> predicateStart = (a) -> a.startsWith("God");

String str = "GodOfJava"

// 데이터가 해당 조건에 맞는지 확인
predicateLength5.test(str)
// 데이터가 두개의 조건에 모두 맞는지 확인
predicateLength5.and(predicateContains).test(str)
// 데이터가 두개의 조건 중 하나라도 맞는지 확인
predicateLength5.or(predicateContains).test(str)
// 데이터가 조건과 다른지 확인
predicateLength5.negate().test(str)

Supplier

  • T get()

Consumer

  • void accept() : 작업을 수행하고 결과를 받을 일 없을 때 사용
  • default Consumer andThen() : 순차적인 작업을 할 때 사용

Function

  • R apply(T t) : 변환을 할 필요가 있을 때 이 인터페이스 사용

UnaryOperator : A unary operator frim T→T

  • R apply(T t) : 한 가지 타입에 대하여 결과도 같은 타입일 경우 사용

BinaryOperator : A binary operator from (T, T) → T

  • R apply(T t, U u) : 한 가지 타입에 대하여 결과도 같은 타입일 경우 사용

stream

  • Collection과 같이 목록(연속된 정보)을 처리할 때 사용
  • 구조
list.stream().filter(x-> x>10).count()
    스트림생성    중개 연산     종단 연산

- 스트림 생성 : 컬렉션 목록을 스트림 객체로 변환 
- 중개 연산 : 생성된 스트림 객체를 사용해 중개 연산 부분에서 처리
             이 부분에서는 아무런 결과를 리턴하지 못한다
             0개 이상의 중개 연산이 존재 
- 종단 연산 : 중개 연선에서 작업된 내용을 바탕으로 결과 리턴 
// 배열 -> 리스트
Integer[] values = { 1, 3, 5 };
List<Integer> list = Arrays.stream(values).collect(Collectiors.toList());

스트림 제공 연산

  • forEach(block) : for 루프를 수행하는 것처럼 각각의 항목을 꺼냄
  • map(mapper) : 데이터를 특정 데이터로 변환
  • 등등
public void printStudentNames(List<StudentDTO> students){
  // student = StudentDTO 객체
  students.stream()
  	.forEach(student -> System.out.println(student.getName()));

  // StudentDTO 객체를 사용하는게 아니라 String값 사용 
  students.stream().map(student->student.getNmae())
  		.forEach(name->System.out.println(name));
}

메소드 참조 = 더블콜론(::)

  • 종류
    • static 메소드 참조
    • 특정 객체의 인스턴스 메소드 참조
    • 특정 유형의 임의의 객체에 대한 인스턴스 메소드 참조
    • 생성자 참조

static 메소드 참조

public class MethodReferenceSample {
   MethodReferenceSampel sample = new MethodReferenceSample();
   String[] stringArray = {"요다", "만두", "건빵"};
   sample.staticReference(stringArray);
} 

public void staticReference(String[] stringArray){
   // of() : 스트림 객체 생성 
   // String의 스트림이기 때문에 forEach() 문장 안에서는 String을 제공
   Stream.of(stringArray).forEach(MethodReferenceSample::printResult);
}

public static void printResult(String value){
   System.out.println(value);
}

특정 객체의 인스턴스 메소드 참조

  • 인스턴스 참조는 System.out::println과 같이 System 클래스에 선언된 out 변수가 있고, 그 out 변수에 있는 println() 메소드를 호출하는 것처럼 "변수에 선언된 메소드 호출"을 의미

특정 유형의 임의의 객체에 대한 인스턴스 메소드 참조

private void objectReference(String[] stringArray){
	// 임의 객체 참조 
	Arrays.sort(stringArray, String::compareToIgnoreCase);
	// 인스턴스 메소드 참조 
	Arrays.asList(stringArray).stream().forEach(System.out::println);
}

public int compareToIgnoreCase(String str){
	return CASE_INSENSITIVE_ORDER.compare(this, str);
}

생성자 참조

interface MakeString{
	String fromBytes(char[] chars);
}

private void createInstance(){
	// String 생성자 중에 char[]를 매개 변수로 받는 생성자가 
        // 있기 때문에 이렇게 사용 가능 
	MakeSring makeString = String::new;
	char[] chars = {'G','O','D'};
	String madeString = makeString.fromBytes(chars);
	System.out.println(madeString);
}

Stream map()

  • 스트림에서 처리하는 값들을 중간에 변경
List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

// initList 내용들 모두 x3하기
intList.stream().forEach(x->System.out.println(x*3)); 
// map() : 스트림에서 처리하는 값들을 중간에 변경할 수 있다. 
intList.stream().map(x->x*3).forEach(System.out::println);

//studentList에서 이름만 List로 뽑아 내고 싶을 경우 
List<StudentDTO> nameList = new ArrayList<>();
studentList.add(new StudentDTO("요다",43,99,10));
studentList.add(new StudentDTO("만두",30,49,90));
studentList.add(new StudentDTO("건빵",32,71,70));
List<String> nameList = studentList.stream().map(x->x.getName())
  			.collect(Collectors.toList());

Stream filter()

  • 필요 없는 데이터나 웹 요청들을 걸러낼 때 사용
private void filterWithScoreForLoop
  		(List<StudentDTO> studentList, int scoreCutLine){
  studentList.stream().filter(student->student.getScore()>scoreCutLine)
  	.forEach(student -> System.out.println(student.getName()));
}

1개의 댓글

comment-user-thumbnail
2021년 8월 14일

아주잘했어요!

답글 달기