Generics add stability to your code by making more of your bugs detectable at complie time.
Benefits of using generics
Stronger type checks at complie time.
A Java complier applies strong type ckecking to generic code and issues errors if the code violates type safety. Fixing complie-time erros is easier than fixing runtime errors, which can be difficult to find.
Elimination of casts.
The following code snippet without generics requires casting:
1 2 3
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);
When re-written to use generics, the code does not require casting:
1 2 3
List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast
Enabling programmers to implement generic algorithms.
By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
Generic Types
Definition: A generic type is generic class or interface that is parameterized over types.
Generic Class
A generic class is defined with the following format:
1
classname<T1, T2, ..., Tn> { /* ... */ }
Type Prameter Naming Conventions
E: Element(used extensively by the Java Collections Framework)
K: Key
N: Number
T: Type
V: Value
S, U, V etc.: 2nd, 3rd, 4th types
Invoking and Instantiating a Generic Type
By performing generic type invocation which replaces T with some concrerate value, such as Integer:
1
Box<Integer> intergerBox;
To instantiate this class, us the new keyword, as usual, but place Integer between the class name and the parenthesis:
1
Box<Integer> integerBox = new Box<Integer>();
Or, In Java SE 7 and later, you can replace the type argument required to invoke the constructor of a gneeric class with an empty set of type argument (<>) as long as the complier can determin, or infer, the type argument from the context.
1
Box<Integer> integerBox = new Box<>();
Multiple Type Parameters
A generic class can have multiple type parameters. For example, the generic OrderedPair class, which implements the generic Pair interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
publicinterfacePair<K, V> { public K getKey(); public V getValue(); }
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter’s scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as class constructors.
The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method’s return type. For static generic methods, the type parameter section must appear before the method’s return type.
The Util class includes a generic method, compare, which compares two pair objects:
publicvoidsetKey(K key){ this.key = key; } publicvoidsetValue(V value){ this.value = value; } public K getKey(){ return key; } public V getValue(){ return value; } }
Bounded Type Parameters
There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
To declare a bounded type parmeter, list hte type parameter’s name. followed by the extends keyword, followed by its upper bound, which in this example is Number. Note that, in this context, extends is used in a general sense to mean either “extends” (as in classed) or “implements” (as in interfaces)
Multiple Bounds
The preceding example illustrates the use of a type parameter with a single bound, but a type parameter can have multiple bounds:
1
<T extends B1 & B2 & B3>
If one of the bounds is class, it must be specified first. For example:
If bound A is not specified first, you get a compile-time error.
Wildcards
In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type. The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.
Unbounded Wildcards
The unbounded wildcard type is specified using the wildcards character (?), for example, List<?>, This is called list of unknown type. There are two senarios where an unbounded wildcard is a useful appoach:
If you are writing a method that can be implemented using functionality provided in the object class.
When the code is using methods in the generic class that don’t depend on the type parameter.
Upperbounded Wildcards
To declare an upper-bounded wildcard, use the wildcard character (?), followed by the extends keyword, followed by its upper bound. Note that, in this context, extends is used in general senese to mean either “extends” (as in classes) or “implements” (as in interfaces).
LowerBounded Wildcards
A lower bounded wildcard is expressed using the wildcard character (?), follwing by the super keyword, followed by its lower bound: <? super A>
Say you want to write a method that puts Integer objects into a list. To maximize flexibility, you would like the method to work on List<Integer>, List<Number>, and List<Object> – anything that can hold Integer values.
Restrictions on Generics
Cannot instantiate generic types with primitypes
1 2
Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error Pair<Integer, Character> p = new Pair<>(8, 'a');
Cannot create instance of type parameters
1 2 3 4
publicstatic <E> voidappend(List<E> list){ E elem = new E(); // complie-time error list.add(elem); }
Cannot declare static fields whose types are type parameters
1 2 3 4
publicclassMobileDevice<T> { privatestatic T os; } // ...
Cananot use cast or instanceof with parameterized types
1 2 3 4 5 6 7 8 9 10
publicstatic <E> voidrtti(List<E> list){ Object obj = new Object(); if (obj instanceof E) { // not possible
Tim Berners-Lee와 그가 속한 팀은 CERN에서 HTML뿐만 아니라 웹 브라우저 및 웹 브라우저 관련 기술과 HTTP를 발명하였다.
문서화된 최초의 HTTP버전은 HTTP v0.9(1991년)이다.
HTTP는 서버와 클라이언트가 인터넷 상에서 데이터를 주고받기 위한 protocol이다.
HTTP는 계속 발전하여 HTTP/2까지 버전이 등장했다.
HTTP 작동방식
HTTP는 Server/Client model을 따른다.
장점
불특정 다수를 대상으로 하는 서비스에는 적합하다.
클라이언트와 서버가 계속 연결된 형태가 아니기 때문에 클라이언트와 서버 간의 최대 연결 수 보다 훨신 더 많은 요청과 응답을 처리할 수 있다.
단점
연결을 끊어버리기 때문에, 클라이언트의 이전 상황을 알 수 없다.
이러한 특징을 무상태(Stateless)라고 한다.
이러한 특징 때문에 정보를 유지하기 위해서 Cookie와 같은 기술이 등장하게 되었다.
HTTP 요청 Method의 구조
요청 Method: GET, PUT, POST, PUSH, OPTIONS등의 요청 방식이 온다.
GET: 정보를 요청하기 위해서 사용 (SELECT)
POST: 정보를 밀어 넣기 위해서 사용 (INSERT)
PUT: 정보를 업데이트하기 위해서 사용 (UPDATE)
DELETE: 정보를 삭제하기 위해서 사용 (DELETE)
HEAD: (HTTP)헤더 정보만 요청한다. 해당 자원이 존재하는지 혹은 서버에 문제가 없는지를 확인하기 위해서 사용한다.
OPTIONS: 웹서버가 지원하는 메서드의 종류를 요청한다.
TRACE: 클라이언트의 요청을 그대로 반환한다. 예컨데 echo 서비스로 서버 상태를 확인하기 위한 목적으로 주로 사용한다.
요청 URI: 요청하는 자원의 위치를 명시한다.
HTTP 프로토콜 버전: 웹 브라우저가 사용하는 프로토콜 버전이다.
URL(Uniform Resource Locator)
인터넷 상의 자원의 위치
특정 웹 서버의 특정 파일에 접근 하기위한 경로 혹은 주소
Web Server
Web Server는 Web Server Software 가 동작하는 컴퓨터를 말한다.
Web Server의 가장 중요한 기능은 Client가 요청하는 HTML문서나 각종 Resource를 전달하는 것이다.
Web brower나 web crawler가 요청하는 Resource는 컴퓨터에 저장된 정적 데이터 이거나 동적인 결과가 될 수 있다.
Web Server Software의 종류
가장 많이 사용하는 웹 서버는 Aphache, Nginx, Microsoft IIS
Apache 웹 서버는 Apache Software Foundation에서 개발한 웹서버로 오픈소스 소프트웨어(Open-source Software)이며, 거의 대부분 운영체제에서 설치 및 사용을 할 수 있다.
Nginx는 차세대 웹서버로 불리며 더 적은 자원으로 더 빠르게 데이터를 서비스하는 것을 목적으로 만들어진 서버이며 Apache웹 서버와 마찬가지로 오픈소스 소프트웨어입니다.
WAS(Web Application Server)
WAS는 일종의 MiddleWare로 Web Client(보통 web browser)의 요청 중 보통 web application이 동작하도록 지원하는 목적을 가진다.
초창기 Web Server는 정적인 content를 주로 제공하였으나 동적인 컨텐츠의 수요가 증가 함에 따라서 WAS가 대두 되게 되었다.
WAS가 보통 웹 서버 기능을 내장하고 있다.
현재는 WAS가 가지고 있는 웹 서버도 정적인 contents를 처리하는데 있어서 성능상 큰 차이가 없다.
규모가 커질수록 웹 서버와 WAS를 분리한다.
자원 이용의 효율성 및 장애 극복 기능(failover), 유지 보수의 편의성을 위해 분리
보통 Web Server가 WAS 앞단에서 동작하도록 한다.
Client/Server 구조
Client는 Service를 제공하는 Server에게 정보를 요청하며 응답 받은 결과를 사용합니다.
DBMS(Database Management System)
다수의 사용자들이 데이터베이스 내의 데이터를 접근할 수 있도록 해주는 소프트웨어
MiddleWare
Client쪽에 비즈니스 로직이 많을 경우, Client 관리(배포 등)로 인해 비용이 많이 발생하는 문제가 발생
비즈니스 로직을 Client와 DBMS사이의 middleware server에서 동작하도록 함으로써 client는 입력과 출력을 담당하도록 함
Apache Tomcat
Apache Tomcat is an open-source implementation of the Java servlet, JavaServer Pages, Java Expression Language and WebSocket technologogies. Tomcat provies a “pure Java” HTTP web server environment in which Java code can run.
Apache Tomcat: The most widley used WAS developed from Apache Software Foundation.
Web Application can run on top of the WAS that is analogous to relation between application and Operating System.
# Implementation of quick sort defquick_sort(array, start, end): if start >= end: return
pivot = start # pick a pivot according to the Hoare Partition left = start + 1 right = end while left <= right: # Loop until find element which is greater than pivot value. while left <= end and array[left] <= array[pivot]: left += 1
# Loop until find element which is less than pivot value. while right > start and array[right] >= array[pivot]: right -= 1
# partition completed if left > right: array[right], array[pivot] = array[pivot], array[right]
# Implementation of MergeSort defmerge_sort(arr): if len(arr) > 1: mid = len(arr) // 2 left = arr[:mid] right = arr[mid:]
merge_sort(left) merge_sort(right)
# Merge i = j = k = 0 while i < len(left) or j < len(right): if i < len(left) and j < len(right): if left[i] < right[j]: arr[k] = left[i] i += 1 else: arr[k] = right[j] j += 1 else: if i < len(left): arr[k] = left[i] i += 1 if j < len(right): arr[k] = right[j] j += 1 k += 1
Count Sort
특정 조건에서 선형 시간에 O(N + K)에서 정렬할 수 있는 알고리즘 이다.
최악의 경우에도 수행시간 O(N + K)를 보장 한다.
일반적으로 가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않을 경우 효과적이다.
데이터 크기가 한정되어 있고, 데이터의 크기가 많이 중복되어 있을수록 유리하며 항상 사용 할 수는 없다.
defbinary_search_iterative(array, target, start, end): while start <= end: mid = (start + end) // 2 if array[mid] == target: return mid elif array[mid] > target: end = mid - 1 else: start = end + 1
returnNone
lower bound
정렬 되어 있을때 해당 값 이상 인 점이 처음 나오는 지점을 찾아 준다.
Python에서는 bisect를 import 하여 사용할 수 있다.
Example
1 2 3 4 5 6 7 8 9
deflower_bound(array, target, start, end): while start <= end: mid = (start + end) // 2 if array[mid] >= target: end = mid - 1 else: start = mid + 1
return start
The try-with-resource Statement
The try-with-resource statement is try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as resource.
Depth-First Search, 깊이 우선 탐색이라고도 부르며, 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘이다.
Java Example
TBD
Python Example
1 2 3 4 5 6 7 8 9 10
# DFS (recursive) method definition defdfs(graph, v, visited): # make visited true for the currently visiting node visited[v] = True print(v, end=" ")
# visiting neighbor node recursively for i in graph[v]: ifnot visited[i]: dfs(graph, i, visited)
BFS
Breath-First Search, 너비 우선 탐색, 가까운 노드부터 시작하여 영역을 점점 넓히며 탐색 하는 알고리즘이다.
Java Example
TBD
Python Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
from collections import deque
# Implementation of BFS method defbfs(graph, start, visited): # using queue queue = deque([start]) # Make visited currently visiting node visited[start] = True # Repeat until queue is empty while queue: v = queue.popleft() print(v, end=" ") # adding node to queue which is not visited and neighbor to current node for i in graph[v]: ifnot visited[i]: queue.append(i) visited[i] = True
Sorting
Selection Sort
매번 가장 작은 것을 선택하여 앞의 인덱스로 옮겨 나가는 알고리즘
선택 정렬의 시간 복잡도: O(N^2)
Python Example
1 2 3 4 5 6 7 8 9
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]
# Implementation Selection Sort for i in range(len(array)) min_index = i for j in range(i + 1, len(array)): if array[min_index] > array[j]: min_index = j array[i], array[min_index] = array[min_index], array[i]
Insertion Sort
필요한 경우 데이터의 위치를 바꾸며 정렬
현재 데이터의 상태와 상관없이 무조건 모든 원소를 비교하고 위치를 바꾸는 선택정렬과 비교
데이터가 일부 정렬되어 있는 경우 유리 이런경우 O(N)에 가깝다.
Python Example
1 2 3 4 5 6 7 8
# Implementation of insertion sort definsertion_sort(array): for i in range(1, len(array)): for j in range(i, 0, -1): if array[j] < array[j - 1]: array[j], array[j - 1] = array[j - 1], array[j] else: break
Java Exception Handling
Exception
Definition: An exception is an event, which occurs during the execution of a program, that distrupt the normal flow of the program’s instructions. When the an error occurs within a method, the method creates an object and hands it off to the runtime system. The object, called exception object, contains information about the error, including its type and the state of the program when the error occured. Creating an exception object and handing it to the runtime system is called throwing an exception.
Advantages of Exceptions
1. Seperating Error-Handling Code from “Regular” Code
Exceptions enable you to write the main flow of your code and to deal with the exceptional cases elsewhere. If the readFile function used exceptions instead of traditional error-management techniques, it would look more like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
readFile { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } }
2. Propagating Errors Up the Call Stack
A second advantage of exceptions is the ablity to propagate error reporting up the call stack of methods.
A method can duck any exceptions thrown within it, thereby allowing a method farther up the call stack to catch it. Hence, only the methods that care about errors have to worry about decting errors
Because of all exceptions thrown within a program are objects, the grouping or categorizing exceptions is a natural outcome of the class hierarchy.
The try Block
The first step in constructing an exception handler is to enclose the code that might throw an exception within try block. In general, a try block looks like the following:
1 2 3 4
try { code } catch and finally blocks...
The segment in the example labeled code contains one or more legal lines of code that throw an exception.
The catch Blocks
You associate exception handlers with a try block by providing one or more catch blocks directly after the try block.
1 2 3 4 5 6 7
try {
} catch (ExceptionType name) {
} catch (ExceptionType name) {
}
Each catch block is an exception handler that handles the the type of exception indicated by its argument. The arguments type, ExceptionType, declares the type of exception that the handler can handle and must be the name of a class that inherits form the Throwable class. The handler can refer to the exception with name.
Exception handlers can do more than just print error messages or halt the program. They can do error recovery, prompt the user to make a decision, or propagate the error up to a higher-level handler using chanined exceptions.
The finally Block
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling – it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in finally block is always a good practice, even when no exceptions are anticipated.
Important: The finally block is a key tool for preventing resource leaks. When closing a file or otherwise recovering resources, place the code in a finally block to ensure that resource is always recovered.
Consider using the try-with-resources statement in these situations, which automatically release system resource when no longer needed.
// 문자열 <-> 기본 자료형 int x = Integer.parseInt("100"); // recommended, parse+자료형, 정적 메소드, 리턴 타입이 int임 int z = Integer.valueOf("200"); // return type Integer unboxing } }
Errors / Exceptions
오류 (Errors)
메모리 부족 또는 프로그램 실행이 꼬이는 경우.
더이상 어떻게 프로그램을 복구해야 할지 알 수 없다.
프로그램의 문제를 해겷하여 해결
예외 (Exceptions)
오류(Error)에 비해서 심각도가 낮고, 프로그램의 정상적인 흐름만 방해
파일을 읽으려 했으나 해당 파일이 없는경우
네트워크 연결 유실
문제 상황을 처리하는 로직을 구현하여, 런타임에서 자연스럽게 해결 가능
예외 처리 (Excpetion handling)
예외가 발생 했을 경우, 이 상황을 ‘감지’하고 ‘처리’하는 코드
try ~ catch, throws, throw, finally 키워드들을 이용
Throwable 클래스를 상속하는 자식클래스들로 이러한 문제를 해결
Throwable Class
Throwable 클래스는 Exception 과 Error 클래스에 의해 상속
Exception
Checked Exceptions: 예외 처리되지 않으면 컴파일이 되지 않은 예외 (file I/O)
Exception Class를 상속하고 있으면 Checked Exception
try ~ catch를 통해 예외를 꼭 처리해 주어야 컴파일이 된다.
Unchecked Exceptions: 예외 처리되지 않아도 컴파일이 되는 예외
RuntimeException 클래스를 상속하고 있으면 Unchecked Exception
try ~ catch를 작성하지 않더라도 빌드/실행 가능
ArrayIndexOutOfBoundsExceptions
ArithmeticException
Error: 프로그램이 복구 불가능한 상황
메소드
설명
public String getMessage()
발생한 예외에 대한 메세지를 반환
public String getLocalizedMessage()
오버라이드하여 추가 메세지 제공 (오버라이드하지 않으면 getMessage()와 동일)
public Throwable getCause()
예외의 원인이 되는 Throwable 객체 반환
public void printStackTrace()
예외가 발생된 메소드가 호출될 때의 Method call stack을 출력
try ~ catch statement
1 2 3 4 5 6 7
try { // 예외가 발생할 수 있는 코드 // 예외가 발생할 경우 예외 객체를 던짐 (throw) } catch (Exception e) { // 던져진 예외를 받음 (catch) // Exception class 및 그 자식 클래스를 사용 // 예외 상황을 처리해야 하는 코드 }
try { // 아주 예민한 내용이 실행되는 부분 // 특정 catch 구문에 선택되는 조건문 // 다형성에 의해서 결정 된다. // 즉, catch 하고 있는 클래스의 자식 클래스의 객체면 catch 가능 // catch 하는 순서가 중요 -> 위에서 부터 자식 객체인 것이 좋다. } catch (ArithmeticException e) {
} catch (FileAlreadyExistsException e) {
} catch (EOFException e) {
} catch (IOException e) {
} catch (Exception e) { // 나머지 모든 Exception 모두 catch // 모든 Exception 객체의 조상 // 권장하지 않음, 무책임한 catch 이다. }
try ~ catch ~ finally
try 구문 실행 중에 어떤 일이 발생해도 반드시 실행되어야 하는 구문은 finally block에 작성
try 구문 내에 return 문이 있는 경우에도 finally 블록은 실행됨
try 구문 내에서 접근한 System 자원을 안전하게 복구하기 위해 사용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
try { file = new FileInputStream("a.txt"); file.read(); } catch (IOException e) { System.out.println("파일 처리 실패"); } finally { System.out.println("파이널리"); if (file != null) { // file 읽기에 실패한 경우 파일을 닫아준다. try { file.close(); } catch (IOException e) { System.out.println("앗!... 아아..."); } } }
try ~ with ~ resource statement
Java1.7에서 추가된 기능
AutoClosable interface를 구현하는 리소스에만 사용가능
1 2 3 4 5
try (FileInputStream file1 = new FileInputStream("a.txt")) { file1.read(); } catch (IOException e) { System.out.println("파일 처리 실패"); }