- 아래 모든 자료구조에 해당하는 클래스, 인터페이스는 언제나 컬렉션 인터페이스 구현함
List - 순서가 있는 데이터 집합 - 데이터 중복 허용 - ArrayList, LinkedList, Stack 등 Set - 순서 유지하지 않는 데이터 집합 - 데이터 중복 허용 안함 - HashSet, TreeSet 등 Map - key와 value의 쌍으로 이뤄진 데이터 집합 (파이썬의 딕셔너리) - 순서 필요 없음 - key 중복 안되지만, value는 중복 허용 - HashMap, TreeMap 등 Stack - 마지막에 넣은 데이터 먼저 꺼내는 자료구조 - LIFO(Last In First Out) - Stack, ArrayDeque 등 Queue - 먼저 넣은 데이터 먼저 꺼내는 자료구조 - FIFO(First In First Out) - ack, ArrayDeque 등
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>(); // List 다음은 해당하는 타입
integerList.add(1);
integerList.add(5);
integerList.add(4);
integerList.add(11);
integerList.add(10);
// ArrayList에 값 한개씩 입력
// 리스트는 add하는 순간 사이즈가 정해짐
// 자료가 많으면 많을수록 그 크기도 늘어남
System.out.println(integerList);
// [1,5,4,11,10] 넣어준 순서대로 출력
Collections.sort(integerList); // integerList 정렬
System.out.println(integerList);
// [1, 4, 5, 10, 11]
System.out.println(integerList.size());
// 5 element 개수만큼 size 출력
integerList.remove(4);
System.out.println(integerList);
// [1, 4, 5, 10]
// 인덱스를 활용하여 해당하는 값 제거
for (int i = 0; i < integerList.size(); i++) {
System.out.println(integerList.get(i));
// get을 이용하여 값 1개씩 출력
}
for (int current : integerList) {
System.out.println(current); // 위와 같은 결과
}
}
}
컬랙션프레임워크 쓰기 위해서는
자료구조를 담는 것은 객체이다 보니 객체를 담을 수 있는 타입이여야함
레퍼런스타입, 즉 참조형 자료
list에서는 primitive타입인 int로 담았는데 이는 참조형 자료가 아니기 때문에 사용할 수 없음
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> integerSet = new HashSet<>(); // Set 다음은 해당하는 타입
integerSet.add(1);
integerSet.add(1);
integerSet.add(3);
integerSet.add(2);
integerSet.add(9);
integerSet.add(8);
System.out.println(integerSet);
// [1, 2, 3, 8, 9]
// 중복된 숫자는 1개만 출력
// 내가 넣어준 순서는 유지되지 않음
Set<String> stringSet = new HashSet<>();
stringSet.add("LA");
stringSet.add("New York");
stringSet.add("LasVegas");
stringSet.add("San Francisco");
stringSet.add("Seoul");
System.out.println(stringSet);
// [San Francisco, New York, LasVegas, LA, Seoul]
// 여전히 순서 유지되지 않음
stringSet.remove("Seoul");
System.out.println(stringSet);
// [San Francisco, New York, LasVegas, LA]
// 순서가 없기 때문에 인덱스로 지울 수 없음
// 정확하게 지정해줘야 함함
List<String> target = new ArrayList<>(); // 여러개 삭제
target.add("New York");
target.add("LasVegas"); // 제거할 항목들 삽입
stringSet.removeAll(target);
// set이나 다른것이 아니더라도 컬렉션타입이면 괄호 안에 뭐든지 올 수있음
System.out.println(stringSet);
// [San Francisco, LA]
System.out.println("LA가 포함되어있나요? " + stringSet.contains("LA"));
System.out.println("LasVegas가 포함되어있나요? " + stringSet.contains("LasVegas"));
// contains() 자료가 포함되었는지 확인하는 함수, true or false return
// LA가 HashSet에 포함되어있으면 true 아니면 false 반환
System.out.println("현재 HashSet의 크기는 : " + stringSet.size() + "입니다.");
//HashSet의 크기 반환
stringSet.clear();// 자료구조 다 지우기
System.out.println(stringSet);
// [] 빈 자료구조 표현
}
}
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>(); // key, value 두개 받아와야 하니 타입 2개 적음
map.put(1, "apple");
map.put(2, "berry");
map.put(3, "cherry");
// map은 add가 아니가 put을 해서 key, value 값 넣어줌
System.out.println(map);
// {1=apple, 2=berry, 3=cherry}
System.out.println("1st in map: " + map.get(1));
// 1st in map: apple
// 첫번째 값 가져오기
// key로 불러오기 때문에 0을 넣으면 null이 나옴
map.remove(2); // 지울 key값 적기
System.out.println(map);
// {1=apple, 3=cherry}
System.out.println(map.containsKey(2));
// false
// 해당 키값 있는지 없는지 확인
System.out.println(map.containsValue("cherry"));
// true
// 해당 벨류 있는지 없는지 확인
// 여기에 key값을 넣으면 value는 String타입인데 Integer타입을 넣었으니 없을거야 라고 알려줌
map.clear(); // 모든 자료구조 삭제
System.out.println(map);
// {}
}
- 가장 먼저 넣은 값인 17이 가장 아래로 가고,
- 이후 삽입되는 값들이 그 위로 쌓임
- pop()을 통해 값을 반환할 때도 마지막에 삽입된 값인 45가 가장 먼저 반환
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>(); // Stack 다음은 해당하는 타입 넣기
stack.push(1); // push로 자료 추가
stack.push(3);
stack.push(7);
stack.push(5);
System.out.println(stack);
// [1, 3, 7, 5] 넣은 순서대로 출력
System.out.println(stack.peek());
// 5 가장 상단에 있는 값 확인만하기
System.out.println("size : " + stack.size());
// 4
// peek은 확인만 하는 것이기 때문에 4 출력
System.out.println(stack.pop());
// 5 삭제한 값 반환
// 가장 상단에 있는 값 삭제
System.out.println("size : " + stack.size());
// 3
// pop은 가장 위에 값을 삭제하는 것이기 때문에 3 출력
System.out.println(stack.contains(1));
// 1이 들어 있으면 true 아니라면 false
System.out.println(stack.empty());
// 마지막에 pop 후 또 pop이 되었는지 확인하기 위해서 사용
// stack이 비어있다면 true 그렇지 않으면 false
stack.clear(); // 모든 자료 삭제
System.out.println(stack.isEmpty());
// stack이 비었다면 true, 아니면 false
System.out.println(stack);
// clear 모든 자료 삭제 했기 때문에 [] 출력
}
}
- 가장 먼저 들어온 Data가 가장 먼저 반환
import java.util.LinkedList;
import java.util.Queue;
public class Main {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 큐는 인터페이스라 구현체가 필요한데 대표적으로 LinkedList
queue.add(1);// add로 값 삽입
queue.add(5);
queue.add(3);
System.out.println(queue);
// [1, 5, 3] 입력된 순서대로 출력
System.out.println(queue.poll());
// 가장 앞에 값 삭제
// 1 삭제한 값 반환
System.out.println(queue);
// [5, 3] poll로 삭제 했기 때문에
System.out.println(queue.peek());
// 5 가장 앞에 있는 값 확인만 하기
System.out.println(queue);
// peek은 확인만 한것이기 때문에 [5, 3] 그대로 출력
System.out.println(queue.isEmpty());
// false
// queue가 비었다면 true, 아니면 false
queue.clear(); // 모든자료 삭제
System.out.println(queue.isEmpty()); // true
System.out.println(queue); // []
}
}
:: deque
- 큐는 한쪽에서만 값이 삽입되고 다른 한쪽에서만 값을 반환하는 자료구조였지만
- deque의 경우 양 끝에서 삽입과 반환이 가능
import java.util.ArrayDeque;
public class Main {
public static void main(String[] args) {
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(); // ArrayDeque를 이용한 선언(제네릭스 이용)
arrayDeque.addFirst(1); // addFirst 첫번째에다 추가
arrayDeque.addFirst(2);
arrayDeque.addFirst(3);
arrayDeque.addFirst(4);
System.out.println(arrayDeque);
// [4, 3, 2, 1] 계속 앞에다가 추가 했으므로
arrayDeque.addLast(0); // addLast 가장 마지막에 추가
System.out.println(arrayDeque);
// [4, 3, 2, 1, 0]
arrayDeque.offerFirst(10);
// 가장 첫번째에 추가
// addFirst와 비슷
// 큐의 크기 문제가 생길 때 offerFirst는 false를 addFrist는 exception을 반환
System.out.println(arrayDeque);
// [10, 4, 3, 2, 1, 0]
arrayDeque.offerLast(-1); // arrayDeque의 가장 끝에 값 삽입
System.out.println(arrayDeque);
// [10, 4, 3, 2, 1, 0, -1]
arrayDeque.push(22); // 22값 가장 앞에 추가
System.out.println(arrayDeque); // [22, 10, 4, 3, 2, 1, 0, -1]
System.out.println(arrayDeque.pop()); // 22 가장 앞에서 꺼내서 보여주고 삭제
System.out.println(arrayDeque); // [10, 4, 3, 2, 1, 0, -1]
System.out.println(arrayDeque.removeFirst());
// 10
// 그냥 remove도 맨앞에 값 제거
// 첫번째 값을 제거하면서 그 값을 리턴
System.out.println(arrayDeque.removeLast());
// -1
// 마지막 값을 제거하면서 그 값을 리턴
System.out.println(arrayDeque); // [4, 3, 2, 1, 0]
System.out.println(arrayDeque.size()); // 5
System.out.println(arrayDeque.pollFirst());
// 4
// 그냥 poll도 맨 앞에 값 제거
// 첫번째 값을 반환 및 제거하면서 그 값을 리턴
System.out.println(arrayDeque.pollLast());
// 0
// 마지막 값을 반환 및 제거하면서 그 값을 리턴
System.out.println(arrayDeque); // [3, 2, 1]
System.out.println(arrayDeque.size()); // 3
System.out.println(arrayDeque.peekFirst());
// 3
// 그냥 peek도 맨 앞에 값 보여줌
// 첫번째 값을 반환, 제거하지 않음
System.out.println(arrayDeque.peekLast());
// 1
// 마지막 값을 반환, 제거하지 않음
System.out.println(arrayDeque.size()); // 3
arrayDeque.clear(); // 전부 삭제
System.out.println(arrayDeque.isEmpty());
// 다 비었다면 true 아니면 false
}
}
공장차리고
거기에 컨베이어 벨트 깔고 물건 싣고 나르는 것도 까는 등 인프라 다 갖춘 후
어떤 날은 코카콜라, 어떤 날은 오렌지 주스, 또 어떤 날은 캔커피 생산한다고 할 때
컨베이어 벨트는
제네릭스를 활용해서 짠 코드, 클래스, 메소드
코카콜라, 오렌지주스, 캔커피는 자바에서 짜는 클래스
public class 클래스명<T> {...}
public interface 인터페이스명<T> {...}
- <T> == Type
- <E> == Element
- <K> == Key
- <V> == Value
- <N> == Number
- <R> == Result (return타입 제네릭스로 할 때 많이 사용)
잘 짜여져있는 제네릭스 구조 파악하기
import java.util.*; public class Main { public static void main(String[] args) { List<String> list = new ArrayList(); // ArrayList의 구현체를 만들어 인터페이스에는 List타입, 변수인 list 만듦 list.add("String"); Collection<String> collection = list; // 만든 list를 List보다 더 상위에 있는 인터페이스인 Collection의 변수에 할당 List<Exception> exceptionList = new ArrayList<>(); Collection<Exception> exceptionCollection = exceptionList; exceptionCollection.addAll(list); // Exception을 상속받은 콜렉션인데 스트링 타입 받는 리스트 써서 빨간 줄 List<IllformedLocaleException> exceptions = new ArrayList<>(); exceptionCollection.addAll(exceptions); // 빨간 줄 사라짐 // exceptionCollection은 Exception 타입에 대한 콜렉션인데 // IllformedLocaleException이 Exception의 자식클래스 중 하나라서 빨간 줄 사라짐
Collection.java 중 일부
Collection<E> 어떤 타입이든 올 수 있는 제네릭스를 이용하는데 Element에 대해 다룰 거라는 뜻 contains 뭐가 있냐~ 라는 함수 확인 할 때 add(E e) E는 어떤 타입이든 올 수 있는 E를 결정 e는 실제로 내가 <String>했을 때는 String이 되고, <Integer>이 되면 Integer가 되는 그 e <T> T[] toArray(T[] a); 맨 위 클래스에서 <>로 선언한 타입이 아닌 경우 이 메소드에서만 쓰이는 어떤 제네릭스를 표현 할 때 가장 왼쪽 <T>로 선언한 것은 이제 어떤 타입을 T라고 표현하고 T라는 제네릭스를 이 메소드에만 사용할 것이라는 표현 toArray -> 어떤 타입을 배열 받아서 배열을 리턴하는 함수 <T>으로 선언하고 이 안에서 타입처럼 사용한다고 이해하면 됨 containsAll(Collection<?> c); ?는 내가 위에서 선언했던 E가 아니여도 된다는 것 아무거나 와도 된다는 말, 특정 클래스 지칭안함 addAll(Collection<? extends E> c); <? extends E> 어떤 것들을 추가할 때에는 다른 콜렉션 넣어서 여러 개 추가할 수 있는데 대신 그 콜렉션은 E라는 타입이거나 E타입을 상속받은 자식클래스만 받겠다는 말 → 잘 짜여져있는 제네릭스 구조 파악하기에 ex 있음
public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); Iterator<E> iterator(); boolean add(E e); <T> T[] toArray(T[] a); boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); }
List.java 중 일부
public interface List<E> extends Collection<E> { // Collection 에 있는 메소드들 모두 포함 // + List 에만 있는 메소드들 // Collection에 있는 E와 같은 타입만 받는다는 의미 boolean add(E e); }
ArrayList.java 중 일부
- 함수의 바디가 있음
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } public E get(int index) { rangeCheck(index); return elementData(index); } public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } }
- 제네릭스는 동작은 같지만 클래스 타입만 바뀌어야 하는 경우 쉽게 다룰 수 있음
- 컴파일언어어의 특징인 타입 안정성을 보장하면서도 유연한 프로그램을 작성할 수 있음
- 대표적인 것은 콜렉션!
ctrl + 클릭으로 명세 확인
람다식이 코드를 보다 간결하게 만들어주는 역할을 하지만 그렇다고 무조건 좋다고만 이야기 할 수는 없음
이유는
- 람다를 사용하여서 만든 익명 함수는 재사용이 불가능
- 람다만을 사용할 경우 비슷한 메소드를 중복되게 생성할 가능성이 있으므로 지저분해질 수 있음
- 똑같은 코드를 또 작성해야 한다면 함수로 만드는 것을 생각해보길
[기존의 메소드 형식] 반환타입 메소드이름(매개변수 선언) { 수행 코드 블록 } [람다식의 형식] 반환타입 메소드이름(매개변수 선언) -> { 수행 코드 블록 }
import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("korea"); list.add("japan"); list.add("france"); Stream<String> stream = list.stream(); // stream은 list에 있는 것을 하나씩 꺼내주는 것을 의미 // stream.map(str -> str.toUpperCase()).forEach(it -> System.out.println(it)); stream.map(str -> { // 사용할 변수 이름 지정(str) System.out.println(str); return str.toUpperCase(); // 이렇게 중괄호를 열어서 사용할 때에는 return 해줘야 함 // }).forEach(it -> System.out.println(it)); }).forEach(System.out::println); // alt + enter로 람다식 표현으로 바꿔주기 // str -> 이런식으로 넘겨주지 않아도 forEach로 넘어온 변수 // 그 파라미터를 이 함수에 자동으로 넘겨준다는 의미 } }
korea KOREA japan JAPAN france FRANCE
스트림 생성
Stream<T> Collection.stream()
중간 연산
- 데이터의 형변환 혹은 필터링, 정렬 등 스트림에 대한 가공을 해줌
- map(변환) / sorted(정렬) / skip(스트림 자르기) / limit(스트림 자르기) 등
1. 기본 구조
import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("서울"); list.add("부산"); list.add("대구"); list.add("서울"); System.out.println(list); // [서울, 부산, 대구, 서울] List<String> result = list.stream() // 스트림 생성 .limit(2) //중간 연산 // 앞에 두개만 남기고 뒤에는 지우는 것 .collect(Collectors.toList()); // 최종 연산 // stream 통해 또 다른 list 만듦 System.out.println(result); // [서울, 부산] System.out.println("list -> transformation -> set"); Set<String> set = list.stream() // list를 set이라는 자료구조로 바꾸기 .filter("서울"::equals) // 람다식 사용 // 받은 문자가 서울이라는 글자와 같다면 .collect(Collectors.toSet()); // set으로 바꿀거야 System.out.println(set); // [서울] // 즉, list 하나씩 꺼내서 서울이라는 글자와 같은지 보고 같은거만 남긴다. // 그리고 set의 자료구조로 바꿔서 모을 것이라는 의미 set.forEach(System.out::println); // 서울 } }
[서울, 부산, 대구, 서울] [서울, 부산] list -> transformation -> set [서울] 서울
2. Array를 Stream으로 변환
import java.util.Arrays; import java.util.stream.Stream; public class Main { public static void main(String[] args) { String[] arr = {"SQL", "Java", "Python"}; Stream<String> stringStream = Arrays.stream(arr); // stringStream.forEach(System.out::println); // // SQL, Java, Python 하나씩 꺼내 출력 stringStream.forEach(className -> System.out.println("수업명 : " + className)); System.out.println(); } }
수업명 : SQL 수업명 : Java 수업명 : Python
3. map연산 활용
- 라이브러리 추가
build.gradle의 dependencies 코드 블록에 붙혀넣기 implementation 'org.apache.commons:commons-lang3:3.0'
- 오른쪽 Gradle 누르고 🔄 클릭
- 외부에 있는 라이브러리 코드를 내 프로젝트에 추가하는 방법
- 코드 추천 같은 것을 잘 받으려면 🔄 버튼 눌러야 함
import org.apache.commons.lang3.tuple.Pair; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; class Sale { String fruitName; int price; float discount; public Sale(String fruitName, int price, float discount) { this.fruitName = fruitName; this.price = price; this.discount = discount; } } public class Main { public static void main(String[] args) { List<Sale> sales = Arrays.asList( new Sale("Apple", 5000, 0.05f), // 5% new Sale("Grape", 3000, 0.1f), // 10% new Sale("Orange", 4000, 0.2f), // 20% new Sale("Tangerine", 2000, 0) // 상품명, 가격, 할인율 ); // 실구매가를 구해서 어떤 과일이 실제로 얼만지 출력 // 즉. 할인된 가격 Stream<Sale> saleStream = sales.stream(); saleStream.map(sale -> Pair.of(sale.fruitName, sale.price * (1 - sale.discount))) .forEach(pair -> System.out.println(pair.getLeft() + " 실 구매가: " + pair.getRight() + "원 ")); } }
Apple 실 구매가: 4750.0원 Grape 실 구매가: 2700.0원 Orange 실 구매가: 3200.0원 Tangerine 실 구매가: 2000.0원
4. reduce를 이용한 계산
- reduce
- integer뿐만 아니라 다른 여러가지 연산도 첫번째 오는 element와 수행할 함수 적용시켜주면 reduce 연산 가능
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); System.out.println(list.stream().reduce(0, Integer::sum)); // 처음을 0으로 시작해서 stream을 하나씩 꺼내서 sum함수 실행할 것이라는 의미 // reduce와 sum을 활용하여 1부터 10까지 더함 // 55 } }
'이'씨 성을 가진 사람들의 수를 세볼려고 합니다. 스트림을 활용해서 코드를 만들어보세요! 스트림을 활용해서 코드를 만들어보세요!
힌트 Javadoc (자바의 클래스 명세)를 확인 후 참고
1. Javadoc1 : startsWith
2. Javadoc2 : count
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = Arrays.asList("김정우", "김호정", "이하늘", "이정희", "박정우", "박지현", "정우석", "이지수"); System.out.println("이씨 성을 가진 친구들 : " + names.stream() .filter(name -> name.startsWith("이")) .count() + "명"); } }
이씨 성을 가진 친구들 : 3명
1. 클라이언트(Client) / 서버(Server) (컴퓨터간의 관계를 역할로 구분)
- 서버 : 서비스를 제공하는 컴퓨터, 요청에 응답하는 컴퓨터
- 클라이언트 : 서비스를 사용하게 되는 컴퓨터, 요청을 하는 컴퓨터
2. IP 주소
- 컴퓨터를 구별하는데 사용된느 고유한 값으로 인터넷에 연결이 되어있는 모든 컴퓨터는 IP 주소를 갖습니다.
내 컴퓨터 IP 주소 확인 CMD -> ipconfig 입력
3. URL(Uniform Resource Locator)
인터넷에 존재하는 여러 서버들이 제공하는 자원에 접근할 수 있는 주소를 표현하기 위한 것
- URL의 형식
- '프로토콜://호스트명:포트번호/경로명/파일명?쿼리스트링#참조' 의 형식
- 프로토콜은 복수의 컴퓨터 사이에서 데이터 통신을 원활하게 하기 위해 필요한 통신 규약을 의미
- 대표적인 예시로는 Http
- 포트번호
- 통신에 사용되는 서버의 포트번호
- 포트(port)는 보통 항구나 공항을 의미하는 것 컴퓨터에서도 포트는 비슷한 역할
- 외부의 다른 장비와 접촉하기 위한 플러그 역할
- 포트번호는 어떤 프로그램에 접속 할 것인지를 식별하는 역할
- 아무것도 입력하지 않으면 기본값은 http는 80번, https는 443 포트
4. API(Application Programming Interface)
- 응용 프로그램에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어 할 수 있게 해주는 인터페이스
- client-server 관점에서 API는 요청과 응답의 형식에 대한 약속
Retrofit 사용하는 이유
- Retrofit을 사용하지 않고 원시적인 방법으로 구현을 하려면, JSON 파싱, 캐싱 등 구현해야할 부분이 너무나 많음
- Retrofit 라이브러리를 사용하게 될 경우 복잡한 구현들을 감소
- 즉, API에 대한 접근을 보다 쉽게 만들어줌
- 각종 에러처리를 쉽게 해결할 수 있으며 원시적인 방법에 비해 가독성 훌륭
- 실제로 프로젝트나 프로그램을 만들 때 공공 데이터 API를 많이 활용
Retrofit 라이브러리 실습 준비 단계
- 3가지 라이브러리가 필요
build.gradle 파일의 dependencies{}에 추가 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.google.code.gson:gson:2.8.5'
- 추가 후 🔄 ( 단축키 : Ctrl + Shift + O )
- 어떤 API에 요청할 것인지 API 확인 -> API 확인을 위한 예제 모아놓은 사이트
- 통신 프로토콜은 https 사용
- GET은 HTTP METHOD중 하나로, 해당하는 데이터 가져옴
- 요청을 하는 도메인(홈페이지 또는 서비스의 주소)은 reqres.in
- 요청을 하는 API의 위치는 /api/users
- 요청을 하는 API에 전달할 데이터는 page=2
- API의 2페이지를 줘! 라는 의미
GET – LIST USERS 확인 request /api/users?page=2 (page=2 == 키=벨류) response 200
쿼리스트링(Query String)
- url 주소에 ?는 쿼리스트링을 작성하겠다는 신호
- 사용자가 입력 데이터를 전달하는 방법중 하나
1. RetrofitService 인터페이스 파일 생성
import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query; public interface RetrofitService { @GET("/api/users/") Call<Object> retrofitTest(@Query("page") int page); } //@Query는 Retrofit 라이브러리를 이용할 때 쿼리스트링을 입력하는 방법 //이렇게 파라미터 변수로 작성해놓으면 함수를 호출할 때 파라미터를 바꿔가며 원하는 페이지를 조회할 수 있음
2. 클라이언트 클래스 생성
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitClient { private static final String BASE_URL = "https://reqres.in/"; // BASE_URL에는 변하지 않는 URL주소를 입력해 주면 됨. 데이터의 위치에 따라 변하지 않는 주소 public static RetrofitService getApi() { return getInstance().create(RetrofitService.class); // api 요청 } // getInstance 메소드를 통해 인스턴스를 반환 private static Retrofit getInstance() { Gson gson = new GsonBuilder().setLenient().create(); // Gson은 JSON 다루는 라이브러리 // 통신을 할 때 JSON 사용 및 해당 객체로의 파싱을 위해 생성 return new Retrofit.Builder().baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); //서버에서는 JSON으로 응답하므로 우리는 build.gradle에 설정한 gson을 이용 }
3. Main
import retrofit2.Call; import java.io.IOException; public class Main { public static void main(String[] args) { Call<Object> retrofitTest = RetrofitClient.getApi().retrofitTest(2); //우리는 2페이지를 확인할 것이기 때문에 2 삽입 //Call은 retrofit라이브러리의 인터페이스이며 서버에서 응답하는 값을 담는 역할 try { System.out.println(retrofitTest.execute().body()); //서버에서 받은 데이터 확인 } catch (IOException e) { System.out.println(e.getMessage()); } } }