직렬화 객체를 전송가능한 형태로 말아주는걸 의미 (java object to json)

역직렬화 그 데이터들을 다시 자바 객체로 변환해주는 걸 의미 (json to java object)

 

java object to json

ObjectMapper mapper = new ObjectMapper();

String json = mapper.writeValueAsString(data); // java Object -> String
jsonNode = mapper.readTree(json); // String -> jsonNode

 

json to java object

JsonResponse response = doPost(request);
JsonNode getResData = response.getResponseBodyAsJson();

ObjectMapper mapper = new ObjectMapper();

String jsonString = mapper.writeValueAsString(data); // json -> String
postCjmallQnaList = mapper.readValue(jsonString,class); // String -> java Object

 

Dependencies jackson-databind

maven

더보기

<dependency>

    <groupId>com.fasterxml.jackson.core</groupId>

    <artifactId>jackson-databind</artifactId>

    <version>2.11.0</version>

</dependency>

gradle

더보기

mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.0'

 

참고 블로그

 -. pjh3749.tistory.com/281

 -. soulduse.tistory.com/22

# chapter 2. 동작 파라미터화 코드 전달하기    

 

-. 동작파라미터화 : 어떻게 실행할 것인지 결정하지 않은 코드 블록

                                이 코드블록은 나중에 프로그램에서 호출. 즉, 코드 블록의 실행은 나중으로 미뤄진다.

    why)) 변화하는 요구사항에 대응하기 위해

    how)) 나중에 실행될 메서드의 인수로 코드블록을 전달할 수 있다.

 

    example) 룸메이트에게 빵, 치즈, 와인등의 식료품을 사달라 부탁

                    작업 수행 메서드 : go 

                    원하는 동작         : go 메서드의 인수

 

[step 1] interfaca 객체를 parameter로 설정

interface ApplePredicate {

    boolean test(Apple a);

}

[step 2] 원하는 조건을 넣어 interface를 구현(implements)하여 클래스 정의

static class AppleRedAndHeavyPredicate implements ApplePredicate {

    @Override

    public boolean test(Apple apple) {

      return apple.getColor() == Color.RED && apple.getWeight() > 150;

    }

}

[step 3] 메서드 사용시 parameter로 구현된 class를 new 로 생성

List<Apple> redAndHeavyApples = filter(inventory, new AppleRedAndHeavyPredicate());

 

=> 이렇게 되면 step2와 같이 로직과 상관없는 소스들이 많아질 수 있다.   

      then, JAVA는 익명클래스를 제공

 

익명클래스 : 클래스의 선언과 인스턴스화를 동시에 수행.

 

익명 클래스를 사용하면 step2step3 단계를 합칠 수 있다.

List<Apple> redAndHeavyApples = filter(inventory, new ApplePredicate() {

    public boolean test(Apple apple) {

        return apple.getColor() == Color.RED && apple.getWeight() > 150;

    }

});

      

가독성이 떨어진다.. 이 부분을 람다로 해결 가능

List<Apple> redAndHeavyApples = 

                        filter(inventory, (Apple apple) -> apple.getColor() == Color.RED && apple.getWeight() > 150 );

 

# chapter 3. 람다 표현식

 

why use)) 동작 파라미터를 이용할 때 익명 클래스 등 판에 박힌 코드를 구현할 필요가 없다.

 

ex1) 커스텀 Comparator 객체

Comparater<Apple> nyWeight = new Comparator<Apple>() {

      public int comparator(Apple a1, Apple a2) {

             ruturn a1.getWeight().comparator(a2.getWeight());

      }

};

 

ex2) 람다 표현식       

Comparater<Apple> nyWeight = (Apple a1, Apple a2) ->  a1.getWeight().comparator(a2.getWeight());

 

    -. (Apple a1, Apple a2)                      : 람다 파라미더

    -. ->                                        : 화살표

    -. a1.getWeight().comparator(a2.getWeight()) : 람다바디

 

함수형 인터페이스 란) 정확히 하나의 추상메서드를 지정하느 인터페이스다. 

 

 

 

#chapter 3. 람다 표현식

 

-. 람다 표현식 : 메서드로 전달할 수 있는 익명함수를 단순화한 것

[example]

Comparator<Apple> byWeight = new Comparator<Apple>() {

    public int compare(Apple a1, Apple a2) {

        return a1.getWeight().compareTo(a2.getWeight());

    }

};

 

[람다 이용]

Comparator<Apple> byWeight = 

    (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

        람다 파라미터   화살표              람다 바디

 

[람다 포멧]

-. (parameters) -> expression

-. (parameters) -> {expression;}

 

-. 함수형 인터페이스  : 정확히 하나의 추상메서드를 지정하는 인터페이스

public interface Comparator<T> {

    boolean test(T t);

}

 

?) 많은 디폴트 메서드가 있더라도 추상 메서드가 오직 하나면 함수형 인터페이스다.

   디포트 메서드 : 인터페이스의 메서드를 구현하지 않은 클래스를

 

@FunctionalInterface 

해당 어노테이션을 쓰면 

 

???) 함수형 인터페이스로 뭘 할 수 있을까?

       람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 전체 표현식을 함수형 인터         페이스의 인스턴스로 취급

 

자바8 설계자들은 java.util.function.* 패키지로 여러가지 새로운 함수형 인터페이스를 제공. 

 

-. Predicate

test 라는 추상 메서드를 정의하며, test는 제네릭형식의 T의 객체를 인수로 받아 불리언을 반환한다.

[java.util.function.Predicate]

       @FunctionalInterface

       public interface Predicate<T> {

             boolean test(T t);

       }

[Predicate 예제]       

       public <T> List<T> filter(List<T> list, Predicate<T> p) {

             List<T> results = new ArrayList<>();

             for (T t:list) {

                    if(p.test(t)) {

                           results.add(t);

                    }

             }

             return results;

       }

       

       Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

       List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

 

-. Comsumer

accept 라는 추상 메서드를 정의하며, accept는 제네릭형식의 T의 객체를 인수로 받아 void를 반환한다.

[java.util.function.Consumer]

       @FunctionalInterface

       public interface Consumer<T> {

             void accept(T t);

       }

[Comsumer 예제]

       public <T> void foreach(List<T> list, Consumer<T> c) {

             for (T t: list) {

                    c.accept(t);

             }

       }

       

       private void forEach() {

             Arrays.asList(1, 2, 3, 4, 5),

             (Integer i) -> System.out.println(i)

       }

 

-. Function

java.util.function.Function<T, R> 인터페이스는 제네릭 형식 T를 인수로 받아서 제네릭 형식 R객체를 반환하는 추상메서드 apply를 정의한다.

[java.util.function.Function]

       @FunctionalInterface

       public interface Function<T, R> {

             R apply(T t);

       }

[Function 예제]

       public <T,R> List<R> map(List<T> list, Function<T, R> f) {

             List<R> result = new ArrayList<>();

             for (T t: list) {

                    result.add(f.apply(t));

             }      

             return result;

       }

       

       List<Integer> l = map(

                    Arrays.asList("lamdas", "in", "action"),

                    (String s) -> s.length()

       );

 

cf> java의 형식

 

     참조형 : Byte, Integer, Object, List

     기본형 : int, double, byte, char

 

-. 박싱         : 기본형 -> 참조형 으로 형 변환

-. 언박싱     : 참조형 -> 기본형 으로 형 변환

-. 오토박싱 : 박싱과 언박싱이 자유롭게 이뤄짐

 

람다로 함수형 인터페이스의 인스턴스를 만들수 있다.

 

[형식검사 문제] 다음 코드를 컴파일할 수 없는 이유는?

 

Object o = () -> { System.out.println("Eun example"); };

 

(solution)

람다 표현식의 콘텍스트 = Object(대상형식) 이다. 

하지만 Object는 함수형 인터페이스가 아니다.

따라서 ()-> void 형식의 함수 디스크립터를 갖는 Runnable로 대상 형식을 바꿔서 문제를 해결할 수 있다.

 

    sol) Object o = (Runnable) () -> { System.out.println("Eun example"); };

 

(추가) 예를 들어 execute (() -> {})라는 람다 표현식이 있다면 Runnable과 Action의 함수 디스크립터가 같으므로 누구를 가리키는지가 명확하지 않다.

 

public void excute(Runnable runnable) {

    runnable.run();

}

public void excute(Action<T> action) {

    action.act();

}

 

@FunctionlInterface

interface Action {

        void act();

}

 

    sol) execute ( (Action) () -> {})

 

-. 형식추론

자바 컴파일러는 람다표현식이 사용된 콘텍스트(대상 형식)를 이용해서 람다 표현식과 관련된 함수형 인터페이스를 추론한다.

[Comparator 객체 예제]

Comparator<Apple> c = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());    // 형식을 추론하지 않음.

Comparator<Apple> c = (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());                // 형식을 추론함

=> 개발자 스스로 어떤 코드가 가독성을 향상 시킬 수 있는지 결정해야 한다.

 

-. 지역변수 사용

 

람다 캡쳐링 :  람다 표현식에서는 익명 함수가 하는 것처럼 자유변수를 활용할 수 있다.

    cf> 자유변수란) 파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수

 

[Question]

int portNumber = 1337;

Runnable r = () -> System.out.println(portNumber);        // 컴파일 ERROR 발생

portNumber = 31337;

 

(solution)

2번째 줄에서 컴파일에러 발생,

    why?) 자유변수의 사용에도 약간의 제약이 있다.

 

지역변수는 final로 선언되어 있어야 한다.

 

final int portNumber = 1337;

Runnable r = () -> System.out.println(portNumber);

portNumber = 31337;                                        // 컴파일 ERROR 발생(final 변수를 수정했으므로)

 

 

[자유변수 사용에 제약이 생긴 이유?]

 

(저장공간)

인스턴스변수 => 힙

지역 변수    => 스택

 

람다에서 지역변수에 바로 접근할 수 있다는 가정하에 람다가 스레드에서 실행된다면 변수를 할당한 스레드가 사라져서 변수 할당이 해제되었는데도 람다를 실행하는 스레드에서는

해당 변수에 접근하려 할 수 있다. 따라서 자바 구현에서는 원래 변수에 접근을 허용하는것이 아닌 자유 지역 변수의 복사본을 제공한다. 

따라서 복사본의 값이 바뀌지 않아야 하므로 지역 변수에서는 한 번만 값을 할당해야 한다는 제약이 생긴것이다.

 

-. 메서드 참조

메서드 참조를 사용함으로써 가독성을 높일 수 있고, 간결하게 구현할 수 있다.

[예제]

inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

inventory.sort(comparing(Apple::getWeight));

 => Apple클래스에 정의된 getWeight의 메서드 참조.

 

생성자, 배열 생성자, super 호출 등에 사용할 수 있는 특별한 형식의 메서드 참조도 있다.

 

1) 기존의 메서드 구현을 재활용해서 메서드 참조를 만드는 방법

[예제] List에 포함된 문자열을 대,소문자를 구분하지 않고 정렬하는 프로그램.

 

List<String> str = Arrays.asList("a", "b", "A", "B");

str.sort((s1, s2) -> s1.compareToIgnoreCase(s2));

str.sort(String::compareToIgnoreCase);

 

2) 생성자 참조 (ClassName::new)

Supplier<Apple> c1 = Apple::new;

Apple a1 = c1.get();                                                      // Supplier의 get메서드를 호출해서 새로운 Apple 객체를 만들 수 있다.

 

Function<Integer, Apple> c2 = Apple::new;              // (weight) -> new Apple(weight)

Apple a2 = c2.apply(110);                                            // Function의 get메서드를 호출해서 새로운 Apple 객체를 만들 수 있다. 

 

 

119 ~ 131 페이지 

생성자 참조~ 부터는 다음에 한번 더 보기! (이해가 잘 안감)

 

 

 

 

 

 

 

 

 

 

# chapter 4. 스트림 소개

 

-. 스트림이란

데이터 컬렉션 반복을 멋지게 처리하는 기능.

cf> 스트림을 이용하면 멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있다.

 

[JAVA 7]

List<Dish> lowColoricDishes = new ArrayList<>();

           

for(Dish dish : menu) {

    if(dish.getCalory() < 400) {

        lowColoricDishes.add(dish);

    }

}

           

Collections.sort(lowColoricDishes, new Comparator<Dish>() {

    public int compare(Dish dish1, Dish dish2) {

        return Integer.compare(dish1.getCalory(),  dish2.getCalory());

    }

});

           

List<String> lowCaloricDishesName = new ArrayList<>();

for(Dish dish : lowColoricDishes) {

    lowCaloricDishesName.add(dish.getName());

}

[JAVA 8]

import static java.util.Comparator.comparing;

import static java.uti;l.stream.Collectors.toList;

 

List<String> lowCaloricDishesName = menu.stream()

                                        .filter(d -> d.getCalory() < 400)              // 400칼로리 이하의 요리  선택

                                        .sorted(comparing(Dish::getCalory))            // 칼로리로 요리  정렬

                                        .map(Dish::getName)                            // 요리명  추출

                                        .collect(toList());                            // 모든  요리명을 리스트에 저장

 

filter 같은 연산은 고수준 빌딩 블록으로 이루어져 있으므로 특정 스레딩 모델에 제한되지 않고 자유롭게 어떤 상황에서든 사용할 수 있다.

결과적으로 우리는 데이터 처리 과정을 병렬화하면서 스레드와 락을 걱정할 필요가 없다. 이 모든 것이 스트림 API 덕분이다.

 

자바 8의 스트림 API 특징

  • 선언형 : 더 간결하고 가동성이 좋아진다.

  • 조립할 수 있음 : 유연성이 좋아진다.

  • 병렬화 : 성능이 좋아진다.

-. 스트림 이란

데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소

 

  • 연속된 요소

            컬렉션과 마찬가지로 스트림은 특정 요소 형식으로 이루어진 연속된 값 집합의 인터페이스를 제공한다.

            but, 컬렉션의 주제는 데이터이고 스트림의 주제는 계산이다.

  • 소스

            스트림은 컬렉션, 배열, I/O 자원등의 데이터 제공 소스로부터 데이터를 소비한다.

            즉, 정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지된다. 

  • 데이터 처리 연산

            스트림은 함수형 프로그래밍 언어에서 일반적으로 지원하는 연산과 데이터베이스와 비슷한 연산을 지원한다.

            ex> filter, map, reduce, find, match

            스트림 연산은 순차적으로 또는 병렬로 실행할 수 있다.

스트림의 중요한 2가지 특징

  • 파이프라이닝

            대부분의 스트림연산은 스트림 연산끼리 연결해서 커다란 파이프 라인을 구성할 수 있도록 스트림 자신을 반환한다.

            연산 파이프라인은 데이터 소스에서 적용하는 데이터베이트 질의와 비슷하다.

  • 내부 반복

            반복자를 이용해서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복을 지원한다.

스트림도 딱 한번만 탐색할 수 있다.

한번 탐색한 요소를 탐색하고 싶다면?) 초기 데이터 소스에서 새로운 스트림을 만들어야 한다.

 

컬렉션과 스트림의 또 다른 차이는 데이터 반복 처리 방법이다.

  • 내부반복 : 스트림

  • 외부반복 : 컬렉션

 

-. 중간연산

스트림을 반환하며 서로 연결할 수 있는 연산

[sample] filter, map, limit 중간연산에 해당

List<String> names = menu.stream()

                                              .filter(dish -> dish.getCalories() > 300)

                                              .map(Dish::getName)

                                              .limit(3)

                                              .collect(toList());

[debug]

List<String> names = menu.stream()

                         .filter(dish -> {

                                    System.out.println("filtering:" + dish.getName());

                                    dish.getCalories() > 300

                                 })

                         .map(dish ->

                                    System.out.println("mapping:" + dish.getName());

                                    return dish.getName();

                                 })

                         .limit(3)

                         .collect(toList());

System.out.println(names);

 

[output]

filtering:pork

mapping:pork

filtering:beef

mapping:beef

filtering:chicken

mapping:chicken

[pork, beef, chicken]

 

=> 하나의 데이터가 중간 연산(filter -> map)과정을 다 돌고나서 다음 데이터를 처리한다.

 

[참고] 중간연산

연산

형식

반환형식

연산의 인수

함수 디스크립터

filter

중간연산

Stream<T>

Predicate<T>

T -> boolean

map

중간연산

Stream<R>

Function<T, R>

T -> R

limit

중간연산

Stream<T>

 

 

sorted

중간연산

Stream<T>

Comparator<T>

(T, T) -> int

distinct

중간연산

Stream<T>

 

 

[참고] 최종연산

연산

형식

반환 형식

목적

forEach

최종연산

void

스트림의 각 요소를 소비하면서 람다를 적용한다.

count

최종연산

long

스트림의 요소 개수를 반환한다

collect

최종연산

 

스트림을 리듀스해서 리스트, 맵, 정수 형식의 컬렉션을 만든다. 

 

 

 

 

 

 

 

 

 

 

* 두 날짜간의 차이를 구하는 함수

1
2
3
4
5
6
7
8
9
10
11
    public static long diffOfDate(String begin, String end) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        
        Date stDt = format.parse(begin);
        Date edDt = format.parse(end);
        
        long diff = edDt.getTime() - stDt.getTime();
        long diffDays = diff / (24 * 60 * 60 * 1000);
        
        return diffDays;
    }
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

* 메인 함수 예제

1
2
3
4
    public static void main(String[] argv) throws Exception {
        long ret = diffOfDate("20191023""20191104");
        System.out.println("ret : " + ret);
    }
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

vue js를 하면서 자바 스크립트 함수도 써보니 정말 좋은거 같다.ㅎㅎ

javascript는 기존의 경험했던 c/c++ 보다 문자열조작에 있어서 상대적으로 쉬운것 같다.

 

- 문자열.split ('element') : element에 따라서 배열을 만들어 준다. 

ex> 'hello my name is eun.'

    => [ "h", "e", "l", "l", "o", " ", "m", "y", " ", "n", "a", "m", "e", " ", "i", "s", " ", "e", "u", "n", "." ]

 

- 배열.reverse() : 배열의 순서를 바꿔준다.

ex> [ "h", "e", "l", "l", "o", " ", "m", "y", " ", "n", "a", "m", "e", " ", "i", "s", " ", "e", "u", "n", "." ]

     => [ ".", "n", "u", "e", " ", "s", "i", " ", "e", "m", "a", "n", " ", "y", "m", " ", "o", "l", "l", "e", "h" ]

 

- 문자열.join('element' : char형 배열을 문자열(string)형으로 만들어준다. element값이 배열 중간중간에 들어간다.

ex1>  .join('')

    [ ".", "n", "u", "e", " ", "s", "i", " ", "e", "m", "a", "n", " ", "y", "m", " ", "o", "l", "l", "e", "h" ]

    => .nue si eman ym olleh

ex2> .join('|')

    [ ".", "n", "u", "e", " ", "s", "i", " ", "e", "m", "a", "n", " ", "y", "m", " ", "o", "l", "l", "e", "h" ]

    => .|n|u|e| |s|i| |e|m|a|n| |y|m| |o|l|l|e|h

'언어 > javascript' 카테고리의 다른 글

[버튼 toggle 처리]  (0) 2019.04.08

// 포맷 설정
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date currentTime = new Date();
String date = format.format(currentTime);

String end_dt = "2019-05-31 00:00:00.0";

Date endDate = format.parse(end_dt);
Date todate = format.parse(date);

System.out.println("endDate:" + endDate);
System.out.println("todate:" + todate);
int compare = endDate.compareTo(todate);

System.out.println("compare:"+ compare);

if(compare >= 0) {
System.out.println("사용가능");
} else {
System.out.println("유효기간만료");
}

'언어 > java' 카테고리의 다른 글

[모던자바 인액션]#4 스트림 소개  (0) 2021.01.13
[JAVA] String으로 입력된 날짜의 차이 구하기  (0) 2019.10.25
자료구조 정리  (0) 2018.12.08
Scanner 정리  (0) 2018.11.29
jar / war 정리  (0) 2018.07.08

/*

* 기간 검색 버튼 css 처리

*/

$('.date_search li').on('click', function() {

$('.date_search button').removeClass('on');

var $this = $(this);

$this.find('button').addClass('on');

});

'언어 > javascript' 카테고리의 다른 글

[문자열 조작 함수] split / reverse / join  (0) 2019.05.30

알고리즘을 공부하면서 사용했던 자료구조들을 정리해보려고 합니다.

추가 사항이 생기면 업데이트 하도록 하겠습니다!


ArrayList - JAVA API

: 배열처럼 크기를 신경쓰지 않아도 되는 자료구조

  • 생성
    ArrayList<Integer> lists = new ArrayList<>();

  • 추가 (add)
    lists.add(10);  // param : index(0~)

  • 삭제 (remove)
    lists.remove(2);  // param : index(0~)

  • 반복 (for)
    for( int iValue : lists) {
        System.out.println(iValue);
    }




BufferedReader

  • 사용하는 이유
    InputStreamReader는 입력을 character로 읽어들인다. Then 문자열로 입력받으려면 불편하다.
    So 생겨난것이 BufferReader 이다.

cf> BufferedReader : InputStreamReader에 버퍼링 기능을 추가한것으로 데이터를 사용자가 요청할때마다 매번 읽어오기 보다는 일정량사이즈로 한번에 읽어온 후 버퍼에 보관한다. 그리고 사용자가 요구할때 버퍼에서 읽어오게 한다. 

결국, BufferedReader를 이용하면 속도를 향상시키고 시간의 부하를 줄일수 있게 된다.

  • 생성
BufferedReader br 
= new BufferedReader
   (new InpuStreamReader(System.in));

  • br.readLine()
    String 형태로 개행문자(엔터)까지 입력받아옴
cf> int형태로 받고 싶은면?
      Integer.parseInt(br.readLine());


StringBuilder

1
2
3
4
5
6
7
8
// 사용법 예시
StringBuilder sb = new StringBuilder();
 
while(!rst.isEmpty()){
    sb.append(rst.pop());
}
 
System.out.println(sb);
cs



Array

1
2
3
4
// 배열 
Int[][] dp = new int[col][row]     // col:5; row:2
=>    11111
      11111
cs



Queue

  • 한쪽 끝에서만 자료를 넣고 다른 한쪽 끝에서만 있는 자료구조 입니다.
  • 먼저 넣은 것이 가장 먼저 나오기 때문에 First In First Out(FIFO) 라고도 합니다.
  • 생성시에 LinkedList의 생성자를 호출한다.
  • offer : 큐에 자료를 넣는 연산
  • Poll : 큐에서 자료를 빼는 연산
  • Front : 큐의 가장 앞에 있는 자료를 보는 연산
  • Back : 큐의 가장 뒤에 있는 자료를 보는 연산
  • Empty : 큐가 비어있는지 아닌지를 알아보는 연산
  • Size : 큐에 저장되어있는 자료의 개수를 알아보는 연산
  • Java 경우에는 java.util.Queue 사용하는 것이 좋다.


Scanner 정리


String

nextLine() : \n를 마침으로 인식.

  즉, 한줄 단위로 입력받기 때문에 개행문자도 한 줄로 인식

next() : 개행문지, 공백문자를 무시하고 문자를 입력받음.

  즉, 개행이나 공백을 마침으로 인식


Int

nextInt() : 공백문자(space)를 마침으로 인식

  즉, String의 next()와 비슷



cf>

https://jicjjang.github.io/2015/08/28/java-foundation1/



알고리즘 공부를 시작하면서 Scanner에 대해서 조금 정리해 봤습니다.

아마도 이 게시물은 매번 업데이트 될 예정입니다.

+ Recent posts