@Overide
-> 상위 클래스의 메서드를 오버라이딩한다는 것을 컴파일러에게 알려줌 (오류 잡아줌)
@Deprecated
-> 새로운 것으로 대체되었으니 기존의 것 사용 안하길 권장할 때
@SuppressWarnings
-> 컴파일 경고 메세지가 나타나지 않도록 함
@FunctionallInterface
-> 함수형 인터페이스의 선언이 바르게 되어있는지 확인
@Target
-> Annotaion 적용할 대상을 지정
@Documented
-> annotaion의 정보가 javadoc으로 작성한 문서에 포함되도록 함
@Inherited
-> 하위 클래스가 Annotaion을 상속받도록 함
@Retention
-> Annotation의 지속 시간을 결정함
@Repeatable
-> Annotaion을 여러 번 붙일 수 있도록 허용
@Target(~~)
@Documented(~~)
@interface Annotation_ex {
타입 요소명();
}
위와 같이 메타 Annotation들을 이용하고, @interface를 쓰면서 사용자 정의 Annotation을 만들 수 있다.
int sum(int num1, int num2){
return num1 + num2;
}
(int num1, int num2) -> {
num1 + num2
}
(int num1, int num2) -> num1 + num2
(num1, num2) -> num1 + num2
위의 4가지는 모두 같은 Lambda식이다.
public class LambdaEx {
public static void main(String[] args) {
ExFucntion exFunction = (num1, num2) -> num1 + num2;
int a = exFunction.sum(10,15);
}
}
interface ExFunction {
public abstract int sum(int num1, int num2);
}
위와 같이 참조변수 타입으로 함수형 인터페이스를 사용하여 원하는 메서드에 접근이 가능하다.
~~
example = () -> {
System.out.println("호출!")'
};
example.accept();
}
매개변수와 리턴값이 없다면 위와 같이 출력이 가능하다.
public class Calculator {
public int add(int x, int y){
return x+y;
}
}
public class ~~ {
psvm {
IntBinaryOperator operator = Calculator::add;
sout(operator.applyAsInt(3,5));
}
}
정적 메서드를 참조할 경우에는 위와 같이 클래스명 :: 메서드의 형태로 쓰면 되고, 인스턴스 메서드의 경우에는 객체를 생성한 뒤 위와 같은 형태로 쓰면 된다.
스트림은 내부 반복자를 사용하게 된다. 이를 사용할 때에 이점은 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맡겨두고, 개발자는 요소 처리 코드에만 집중할 수 있다는 것이다. 그리고 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있게 도와준다.
Stream<String> = list.stream();
Stream<String> = Stream.of("a","b","c");
Stream<String> = Stream.of(new String[] {"a","b","c"});
Stream<String> = Arrays.stream(new String[] {"a","b","c"});
IntStream stream = IntStream.range(4,10) // 4~9
list.stream()
.distinct() //중복 제거
.filter(n -> n != 1) //람다식 이용한 중복 제거
. ~~
list.stream()
.map(s -> s.toUpperCase()) //기존 Stream 요소들 대체하는 Stream 형성
. ~~
list.stream()
.sorted(Comparator.reverseOrder) //기존 오름차순, reverseOrder 작성하면 내림차순
. ~~
list.stream()
.peek(n -> sout(n)) //요소 하나씩 돌면서 출력하지만 중간 연산자
. ~~
list.stream()
. ~~
.forEach(n -> sout(n));
list.stream()
. ~~
.allMatch(a -> a%2 == 0); // boolean값 반환
list.stream()
. ~~
.sum(); //count, average, max, min 등이 있다.
list.stream()
. ~~
.collect(Collectors.toList()); //List 형태로 수집
list.stream()
. ~~
.collect(Collectors.toCollection(HashSet :: new));
~~
public class ThreadExample {
psvm{
Runnable task1 = new ThreadTask1();
Thread thread1 = new Thread(task1);
thread1.start();
ThreadTask2 thread2 = new ThreadTask2();
thread2.start();
}
}
class Threadtask1 implements Runnable {
public void run(){
~~
}
}
class Threadtask2 extends Thread {
public void run(){
~~
}
}
Thread thread1 = new Thread(new Runnable() {
public void run() {
~~
}
});
Thread thread2 = new Thread() {
public void run() {
~~
}
}
위의 방법들로 익명 객체를 이용한 스레드 생성 및 실행을 할 수도 있다.
main문에서 Thread를 2개 생성한 뒤 thread.start()를 각각 입력한다고 하자. 그렇게 되면 두 스레드가 동시에 실행 되는데, 이 때 두개의 작업 스레드가 생성되고 이것은 같은 객체를 공유하게 된다. 이때 그 안에 연산이 들어가 있다면 오류가 생길 수도 있다. 따라서 두 개의 스레드가 동시에 실행하면 안 되는 영역을 설정해 그러한 오류를 막아야 한다.
class Account {
~~
public synchronized boolean withdraw(int money) {
~~
}
}
class Account {
~~
public boolean withdraw(int money) {
synchronized (this) {
~~
}
}
}
위와 같은 두가지의 방법으로 임계 영역을 지정하여 스레드의 동기화를 이뤄낼 수 있다. 이렇게 할 시에 같은 객체를 공유하는 경우 두 개의 스레드가 동시에 실행되지 않아 오류가 생기지 않게 된다.