[12.01] 내일배움캠프[Spring] TIL-23

박상훈·2022년 12월 1일
0

내일배움캠프[TIL]

목록 보기
23/72

[12.01] 내일배움캠프[Spring] TIL-23

1. Java Interface 다시 이해하기

  • Interface : 인터페이스를 사이로 앞, 뒤의 개발 코드가 서로 통신하는 접점. 앞, 뒤의 통신 규약 → 동시 개발 가능

인터페이스 정리

interface Practice {
	// 상수
	(final/static : 지우라고뜸) 타입 상수명(대문자 convention) =;
	String HI = "Hi~";

	// 추상 메서드
	List<String> findAllName();

	// Default 메소드
	default 타입 메소드명(파라미터,...) {...}
	default void printHi() {
		System.out.println(HI);
	}

	// static 메소드
	static void printHi() {
		System.out.println(HI);
	}
}

1) 상수만 가능 → 클래스 로드 시점에 초기화

public static final 가 컴파일 시점에 붙는다.

2) 추상메서드로 구현체에게 구현 강제
3) 기본 메서드 제공
→ 자바는 단일 상속, 다중 구현을 제공 → 만약 두개의 인터페이스를 구현했는데, 두 인터페이스의 메서드 명이 똑같다면 어떻게 되나?? → 충돌나는 메서드 시그니처의 오버라이딩을 강제화!
→ public 생략시 컴파일 과정에서 자동으로 붙여줌
4) Static메소드 → 헬퍼 또는 유틸리티 메소드를 제공할 때 사용

인터페이스 써보기

public interface Practice {

    String HI = "HI~"; // 상수 정의 가능 컴파일 시 앞에 static finald이 붙는다고 생각하기!

    default void printHi(){
    //java 8 이상부터 기본 메소드 사용가능
        System.out.println("default "+ HI);
    }

    static void printHI(){
    //static 메소드 사용가능
        System.out.println("static "+ HI);
    }
}
public class Example implements Practice{

    public void print(){
        System.out.println(HI);
    }

    public void defaultMethod(){
    //원래 인터페이스는 함수 껍대기만 있기 때문에 구현해서 완성 시키는 것 이였는데, 이렇게 기본메서드를
    //제공한다.
        printHi();
    }

    public void staticMethod(){
        Practice.printHI();
    }


    public static void main(String[] args) {
        Example ex = new Example();

        ex.print();
        ex.defaultMethod();
        ex.staticMethod();
           // HI~
           // default HI~
           // static HI~
    }
}

인터페이스, 추상클레스

1) 인터페이스 -> 다중 구현 / 추상클레스 -> 단일 상속
2) 인터페이스 -> 어떤 공통된 속성을 가지고 구현한다 / 추상클레스 -> 속성을 상속받아 확장시키는 것
3) 인터페이스의 접근제어자는 public만 가능 -> 공개 목적이기 때문!!

2. 다형성 구현기술

자동형변환( Promotion ) / 강제형변환( Casting )

  • Java에서는 같은 타입끼리의 연산을 제공한다.
  • Ex) Int + Int = true ;
    Ex) int + Double = false ; -> 이럴 때 형변환 필요하다!!!

자동형변환( Promotion )

  • 이런식으로 작은 데이터 타입 -> 큰 데이터 타입으로의 변환은 자동으로 형변환이 일어난다.
  • long 타입의 메모리는 8byte인데 float로 자동 형변환이 가능한 이유는 float가 표현범위가 더 크기 때문이다.
  • byte 타입 -> char 타입 : 자동 형변환 불가
  • float 타입 -> long 타입 : 자동 향변환 불가
  • 인터페이스로 보는 자동 형변환
    -> 인터페이스 변수 = 구현객체; ← 자동 타입 변환
    -> Interface clazz = new InterfaceImplementClass();
    -> List< > arr = new ArrayList< >( ); 이것 또한 List인터페이스로 자동 형변환인가?

    👉 큰 데이터 타입 = 작은 데이터 타입 -> 자동 형변환이 이루어짐

강제형변환( Casting )

상위 인터페이스, 클래스, 추상 클래스로 Upcasting 가능
→ 모든 클래스는 extends Object 가 생략되어있다.
→ 모든 클래스는 Object로 Upcasting 가능

    int i = 10;
    double j = 5.5;

    double result = i + j; // 15.5 

3. 함수형 인터페이스와 람다표현식

추상메소드를 하나만 갖고있는 인터페이스

@FuntionalInterface 애노테이션을 인터페이스에 선언하면 컴파일 시점에서 추상메소드를 하나만 갖는지 체크해 준다.

@FunctionalInterface
public interface Sum {
    int intSum(int x, int y);
}

람다 표현식

  • 메소드를 하나의 식으로 표현한 것( 쉽게 이야기 하자면 )
List<String> list = new ArrayList();
list.add("Element1");
list.add("Element2");
list.add("Element3");

list.forEach(x -> System.out.println(x))
// 위 코드는 list.forEach(System.out::println) 으로 축약할 수 있음
// 원래라면 for문 돌려야 함!..

4. 스트림( Stream )

스트림이란?

  • 스트림은 데이터를 변경하지 않는다.
  • 스트림 연산이 끝난 후 재 사용할 수 없다.

스트림 파이프라인

  • 0 ~ N 개의 중간 연산과 1개의 종료 연산으로 구성.
  • 내가 사용했을 때의 경험은 중간 filter,map...등등이 여러개 붙은 후 forEach()로 마무리 했던 경험

중개연산

  • Stream을 리턴

종료 연산

  • Stream을 리턴하지 않는다.

중개연산 종류

  • 필터링 : filter , distinct
  • 변환 : map , faltMap
  • 제한 : limit , skip
  • 정렬 : sort

종료연산 종류

  • 요소 출력 : forEach
  • 요소 검색 : findFirst , findAny
  • 요소 통계 : count , min, max
  • 요소 연산 : sum , average
  • 요소 수집 : collect

5. Optional

Optional 이란?

잘못된 Optional 사용

  • NPE는 물론, NoSuchElementException이 발생함.
  • 잘못된 Optional사용으로 새로운 문제들이 발생함
  • 코드의 가독성을 파괴
  • 시간, 공간적 비용이 증가함
  • Null을 반환하면 오류가 발생할 가능성이 매우 높은 경우에 "결과없음"을 명확하게 드러내기 위해 메소드의 반환 타입으로 사용되도록 매우 제한적인 경우로 설계 됨.
    🚨 Optional은 메소드의 반환형으로만 사용가능!!!!! 🚨

Optional 객체 꺼내는 방법

Optional<String> opt = Optional.ofNullable("Optional은 Wrapper Class");

System.out.println(opt.get());

Optional 예제 만들어보기

  • empty( )
import java.util.Optional;

public class Example {

   Optional<String> empty = Optional.empty();
   
    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.empty.isPresent()); // false
    }
}
  • of( )
    🚨 of( ) 는 null이 아님을 확신할 때 사용.
import java.util.Optional;

public class Example {

    Optional<String> empty = Optional.of("assert NotNull");
    
    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.empty.isPresent());
    }
}
  • ofNullalbe( )
import java.util.Optional;

public class Example {

    Optional<String> empty = Optional.ofNullable(null);
    
    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.empty.isPresent());
    }
}
  • ifPresent( )
    👉 Optional에서 꺼낸 객체가 존재한다면, 구문수행
import java.util.Optional;

public class Example {

    String name = null;
    Optional<String> opt = Optional.ofNullable(name);
    
    public static void main(String[] args) {
        Example ex = new Example();
        ex.opt.ifPresent(s -> System.out.println(s)); // null이기 때문에 아무 값도 없음 
    }
}
  • OrElse( )
    👉 Optional에서 꺼낸 객체가 존재한다면 꺼내고 그렇지 않으면,orElse의 인자값을 반환
import java.util.Optional;

public class Example {

    String name = null;
    Optional<String> opt = Optional.ofNullable(name);

    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.opt.orElse("값이 없어요!!"));//값이 없어요!! 출력
    }
}
  • OrElseGet( )
    👉 OrElse( ) 와 비슷하지만, 인자값으로 람다 표현식의 결과값을 출력
import java.util.Optional;

public class Example {

    String name = null;
    Optional<String> opt = Optional.ofNullable(name);

    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.opt.orElseGet(()->"값이 없는데요?"));// 값이 없는데요? 출력
    }
}
  • orElseThrow( )
    👉 Optional에서 꺼낸 객체가 존재한다면 꺼내고, 그렇지 않다면? Exception 던지기
import java.util.Optional;

public class Example {

    String name = null;
    Optional<String> opt = Optional.ofNullable(name);

    public static void main(String[] args) {
        Example ex = new Example();
        System.out.println(ex.opt.orElseThrow(IllegalAccessError::new));//IllegalAccessError터짐
    }
}

번외) Stream 인상 깊은 예제 사용해보기

mport java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Example {

    List<Person> person = Arrays.asList(
            new Person("park",20),
            new Person("kim",30),
            new Person("Lee", 40)
    );
    List<String> personName = person.stream().map(Person::getName).collect(Collectors.toList());

    public static void main(String[] args) {
        Example ex = new Example();
        ex.personName.stream().forEach(System.out::println);
    }
}

👉 이름과 나이를 가진 Person클레스를 객체로 가진 List 타입의 person에서 Name필드만 뽑아와서 따로 List로 저장해주는 부분
👉 원래 같았으면 for 반복문을 person.length만큼 돌려주면서 get(i).getName()해온 것을 String 타입을 가진 personName List에 add 해줘야 하는데 코드도 길어지고, 가독성이 떨어질 수 있다.
👉 이러한 Stream을 사용함으로써 간단한 코드 한줄로 위의 반복작업을 간단하게 해결할 수 있다.

6. Java - 프로그래머스 - Level 1

1.가운데 문자열 가져오기 문제

  • 정수형 문자 배열에서 중간 수를 가져오기
  • 만약 문자열의 길이가 짝수일 경우 두개를 가져오게 된다.
 import java.util.Arrays;
 
 class Solution {
     //가운데 글자 가져오기
     // 가운데 글자를 가져오기
     // 단어 길이가 홀수 = 가운데 한글자만 5 -> 3 7 -> 4 9 -> 5
     // 단어 길이가 짝수 = 가운데 두글자만
 
     public String solution(String s) {
 
         char[] arr = s.toCharArray();
         String answer;

 
         if(arr.length%2==0){
           char a = arr[arr.length/2-1];
           char b = arr[(arr.length/2)];
            answer = String.valueOf(a)+String.valueOf(b);
         }else{
            char a = arr[(arr.length/2)];
            answer = String.valueOf(a);
         }

         return answer;
 
     }
 
     public static void main(String[] args) {
         Solution sol = new Solution();
         System.out.println(sol.solution("qwer"));
    }
}

2.연속되지 않는 숫자 출력하기

  • 정수형 배열이 주어진다.
  • [1,1,3,3,0,1] -> [1,3,0,1] 이 출력되어야 하며 순서가 보장되어야 함
  • Set자료구조는 못쓰겠구나~
import java.util.*;

public class Solution {
    //0~9까지의 숫자로 이루어진 int 배열 arr이 주어진다.
    // 오케이 확인
    public List<Integer> solution(int []arr) {
        List<Integer> answer = new ArrayList<>();

       for(int i=0;i<arr.length-1;i++){
           if(i==0){
               answer.add(arr[i]);
           }
           if(arr[i]!=arr[i+1]){
               answer.add(arr[i+1]);
           }
       }
        return answer;
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        sol.solution(new int[]{1,1,3,3,0,1,1}).stream().forEach(s-> System.out.println(s));
    }
}

3. 나눠 떨어지는 숫자 오름차순 뱉어내기

  • 중복되지 않는 자연수를 가진 정수형 배열과, 나눌 자연수가 주어진다.
  • 나누는 수로 나눠떨어지는 숫자들을 오름차순으로 출력하기
  • 만약 나눠 떨어지는 숫자가 없다면 [-1] 반환하기

import java.util.Arrays;



class Solution {

    //arr 의 각 요소중에서 divisor로 나눠떨어지는 값을 오른차순으로 정렬한 배열을 반환해라
    public int[] solution(int[] arr, int divisor) {

        int count = 0;
        for(int i=0;i<arr.length;i++){
            if(arr[i]%divisor==0){
                count++;
            }
        }

        if(count==0){
            return new int[]{-1};
        }

        int [] answer = new int[count];
        for(int j=0;j<arr.length;j++){
            if(arr[j]%divisor==0){
                answer[count-1] = arr[j];
                count--;
            }
        }
        Arrays.sort(answer);
      return answer;

    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        System.out.println(Arrays.toString(sol.solution(new int[]{2,36,1,3},1)));

    }


}
profile
기록하는 습관

0개의 댓글