java.lang 패키지

java.lang

  • Java에서 가장 기본적이며 자주 사용되는 클래스를 모은 패키지
  • 별도로 import하지 않아도 사용이 가능한, Java의 기본 중의 기본

Object Class

  • 모든 클래스의 조상 클래스로, 클래스가 갖춰야할 기본 기능을 제공

  • 필요한 경우 Object 클래스에 정의된 메소드를 Override하여 사용

    메소드 설명
    public final native Class<?> getClass() 현재 객체의 클래스를 반환한다.
    public native int hashCode() 현재 객체의 해시코드 값을 반환한다.
    public boolean equals() 현재 객체와 대상이 같은 객체를 참조하는지 여부를 반환한다.
    public String toString() 객체를 문자열로 변환하여 반환한다.
    proteted native clone() throws CloneNotSupportedException 객체를 복사하여 새로운 객체로 반환한다.

equals()

  • Object 클래스의 equals() 메소드 구현

    • 객체의 참조만을 비교
    1
    2
    3
    public boolean equals(Object obj) {
    return (this == obj);
    }
  • String 클래스의 equals() 메소드 구현 (Overriding)

    • 효율적으로 객체의 내용이 동일한지 비교
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public boolean equals(Object anObject) {
    if (this == anObject) {
    return true;
    }
    if (anObject instanceof String) {
    String aString = (String)anObject;
    if (!COMPACT_STRINGS || this.coder == aString.coder) {
    return StringLatin1.equals(value, aString.value);
    }
    }
    return false;
    }

hashCode()

  • 객체를 구분하기 위해 사용하는 정수값(해시코드)을 반환
    • 프로그램 내에서 객체마다 유일하므로 주소값처럼 사용 가능
  • native 메소드이므로 구현 내용을 볼 수 없음
  • hashCode()의 제한 사항
    • 한 객체의 hashCode()를 여러번 호출할 경우, equals()에 사용하는 값이 변하지 않으면 동일한 값을 반환해야 한다.
    • equals() 메소드가 같다고 판단한 두 객체의 hashCode() 반환값은 같아야 한다.
    • equals() 메소드가 다르다고 판단한 두 객체의 hashCode()가 반드시 다를 필요는 없으나, 다른 값이 나오면 HashTable 성능이 향상된다.

clone()

  • 자신을 복제하여 새로운 객체를 생성하는 메소드

  • 배열을 복제할 경우 새로운 객체를 생성하므로 원본을 훼손하지 않을 수 있음

  • clone() override 시 Cloneable 인터페이스를 구현해야 함

    1
    2
    int [] ints = {1, 2, 3, 4, 5};
    int [] ints2 = ints.clone();

getClass()

  • Class 에 대한 정보를 담고 있는 Class 객체를 반환

  • 객체의 getClass() 메소드 또는 해당 클래스의 정적 변수 class를 이용 가능

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Foo {
    public void methodA() {
    System.out.println("method A called.");
    }
    }

    class FooTest {
    public static void main(String[] args) throws Exception {
    Foo foo = new Foo();
    Class fooClass = foo.getClass();

    System.out.println(fooClass.getName());
    System.out.println(fooClass.getDeclaredMethods().length);
    System.out.println(Foo.class.getDeclaredMethod("methodA").invoke(foo));
    }
    }

System

  • 실행 중인 OS와 interact하기 위한 클래스

  • System 클래스의 주요 정적 변수

    속성 설명
    public static final PrintStream err 오류를 출력하기 위한 표준 출력 스트림
    public static final InputStream in 표준 입력을 처리하기 위한 입력 스트림
    public static final PrintStream out 표준 출력을 처리하기 위한 출력 스트림
  • System 클래스의 주요 정적 메소드

    메소드 설명
    arraycopy() src 배열의 내용을 dst 배열로 복사한다.
    currentTimeMillis() 현재 시스템 시간을 ms로 반환한다.
    exit() 프로그램을 종료한다
    gc() GC를 요청한다.
    getenv() 환경 변수의 값을 반환한다.
    getProperties() 시스템 속성을 Property로 반환한다.
    getProperty() 시스템 속성 값을 문자열로 반환한다. 없을 경우 null 또는 def를 반환
    identityHashCode() 객체의 해시코드 값을 반환한다.
    lineSeparator() 시스템의 줄넘김 문자열을 반환한다. UNIX: \n, WINDOWS: \r\n
    nanoTime() 시스템 시간을 ns로 반환한다.
    setProperties() 시스템 속성을 한번에 설정한다.
    setProperty() 시스템 속성을 하나씩 설정한다.
    • 주요 Property

      속성 설명
      user.country OS 로케일 정보
      java.io.tmpdir 임시 경로
      line.separator 줄넘김 문자열
      user.home 유저 홈 경로
      file.separator 파일 경로 구분

Math

  • 수학 계산에 필요한 메소드를 가진 final 클래스

    메소드 설명
    abs() 절대값을 반환한다.
    ceil() 올림 값을 double로 반환한다.
    floor() 내림 값을 double로 반환한다.
    max() 두 값 중 더 큰 값을 반환한다.
    min() 두 값 중 더 작은 값을 반환한다.
    random() 0 이상 1.0 미만의 임의의 값을 반환한다.
    round() 소수점 첫째자리에서 반올림한 정수 값을 반환한다.
    addExact() 덧셈 연산으로, Overflow 발생 시 ArithmaticException 발생.
    subtractExact() 뺄셈 연산으로, Overflow 발생 시 ArithmaticException 발생.
    multiplyExact() 곱셈 연산으로, Overflow 발생 시 ArithmaticException 발생.

Comment and share

스트림 API (Stream API)

스트림 API란

  • Java 8에서 추가된 java.util.stream 패키지
  • 컬렉션의 요소를 람다식으로 처리할 수 있도록 하는 함수형 프로그래밍 도구

스트림 API의 특징

  • 간결한 코드 작성
1
2
3
4
5
6
7
8
9
10
11
// JAVA 7
List<String> list = Arrays.asList("fast", "campus", "rocks");
List<String> newList = new ArrayList<>();

for (String s: list) {
newList.add(s.toUpperCase());
}

for (String s: newList) {
System.out.println(s);
}
1
2
3
4
// JAVA 8
List<String> list = Arrays.asList("fast", "campus", "rocks");
Stream<String> stream = list.stream();
stream.map(String::toUpperCase).forEach(System.out::println);
  • 데이터 소스에 대한 공통의 접근 방식 제공

    • List, Set, Array 등 다양한 경우에 대해 표준화된 방식으로 데이터 접근 가능
    • 특히 Stream::sorted() 메소드는 공통된 정렬 방식을 제공
  • 중간 처리와 최종 처리를 지원

    • Mapping, Filtering, Sorting 등 중간 처리 지원 (여러개 사용 가능)
    • Iteration, Count, Average, Summation, Reduce 등 최종 처리 지원 (마지막에 하나 사용 가능)
  • 데이터 소스와 처리 결과를 분리

    • 원본 데이터를 유지하여 처리에 의한 부작용 방지
    • 처리 결과를 새로운 컬렉션으로 저장 가능

스트림 API를 이용한 자료 처리

스트림 API의 종류

종류 처리 대상
Stream<T> 일반적인 객체를 처리
IntStream 기본 자료형 int를 처리
LongStream 기본 자료형 long을 처리
DoubleStream 기본 자료형 double을 처리

스트림 객체 생성 메소드

  • 데이터 소스로부터 스트림 생성

    데이터 소스 메소드
    Collection default Stream<E> stream()
    Collection default Stream<E> parallelStream()
    Arrays public static <T> Stream<T> stream(T[] array)
    Arrays public static <T> Stream<T> of(T ... values)
    Arrays public static IntStream stream(int[] array)
    Arrays public static IntStream of(int ... values)
    Arrays public static LongStream stream(long[] array)
    Arrays public static LongStream of(long ... values)
    Arrays public static DoubleStream stream(double[] array)
    Arrays public static DoubleStream of(double ... values)
  • 정수 범위와 java.util.Random으로부터 생성

    구분 메소드
    int형 범위 public static IntStream range(int startInclusive, int endExclusive)
    int형 범위 public static IntStream rangeClosed(int startInclusive, int endInclusive)
    long형 범위 public static LongStream range(long startInclusive, long endExclusive)
    long형 범위 public static LongStream rangeClosed(long startInclusive, long endInclusive)
    Random p형 값 public PStream ps()
    Random p형 값 public PStream ps(long streamSize)
    Random p형 값 public PStream ps(long streamSize, p origin, p bound)
    1
    2
    3
    4
    5
    6
    IntStream integers = IntStream.range(0, 10);
    integers.forEach(System.out::println);

    Random random = new Random();
    LongStream longs = random.longs(100, 1, 10);
    System.out.println(longs.average().getAsDouble());

중간 처리 메소드

동작 메소드
필터링 dinstict(), filter()
자르기 skip(), limit()
정렬 sorted()
매핑 flatMap(), flatMapToP(), map(), mapToP(), asDoubleStream(), asLongStream()
조회 peek()

필터링

필터링은 스트림의 일부 요소를 제거하는 역할을 한다.

  • Stream<T> distict() : 스트림 요소의 중복을 제거한 스트림을 반환
  • Stream<T> filter(Predicate<? super T> predicate) : Predicate에서 true에 해당하는 요소만으로 구성된 스트림을 반환

자르기

자르기는 스트림의 일부 요소를 한번에 생략한다.

  • Stream<T> limit(long maxSize) : 최대 maxSize까지 구성된 스트림을 반환
  • Stream<T> skip(long n) : 스트림의 상위 n개 요소를 생략한 스트림을 반환

정렬

스트림 요소의 compareTo() 또는 입력받은 Comparator를 이용해 정렬

  • Stream<T> sorted() : Comparable 객체를 정렬한 스트림 반환
  • Stream<T> sorted(Comparator<? super T> comparator) : Comparator를 이용하여 정렬된 스트림 반환
    • Comparator의 정적 메소드와 기본 메소드
      • 정적 메소드: naturalOrder(), reverseOrder(), comparing(), comparingP(), nullsFirst(), nullsLast()
      • 기본 메소드: reversed(), thenComparing(), thenComparingP()

매핑

Function 인터페이스를 이용해 요소의 값을 변환한다.

  • map 계열

    • <R> Stream<R> map(Function<? super T, ? extends R> mapper) : 기존 스트림의 T 타입 요소를 R 타입으로 변환하여 새로운 스트림 반환
    • PStream mapToP(ToPFunction<? super T> mapper) : R이 기본형 타입으로 제한된 map()
  • flatMap 계열

    • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) : 스트림의 T 타입 요소가 n개의 R 타입 요소로 매핑된 새로운 스트림을 반환
    • PStream flatMapToP(Function<? super T, ? extends PStream> mapper) : R이 기본형 타입으로 제한된 flatMap()
    1
    2
    3
    4
    List<String> list = Arrays.asList("java", "backend", "best", "course");
    System.out.println(list.stream().flatMap(data -> {
    return Arrays.stream(data.split(""));
    }).distinct().count());

조회

스트림 처리 과정에 영향을 미치지 않으며, 중간 결과를 확인할 수 있으며 입력받은 스트림과 동일한 스트림을 반환한다.

  • Stream<T> peek(Consumer<? super T> action)

    1
    2
    3
    4
    5
    6
    List<String> list = Arrays.asList("java", "backend", "best", "course");
    System.out.println(list.stream().flatMap(data -> {
    return Arrays.stream(data.split(""));
    }).peek(s -> System.out.println("flatMap:" + s))
    .distinct().peek(s -> System.out.println("distinct:" + s))
    .count());

최종 처리 메소드

동작 메소드
매칭 allMatch(), anyMatch(), noneMatch()
수집 collect()
루핑 forEach()
집계 count(), max(), min(), average(), sum(), reduce()
조사 findFirst(), findAny()

매칭

Predicate 계열을 이용해 스트림 요소들이 특정 조건에 만족하는지 조사하는 메소드

  • boolean allMatch(Predicate<? super T> predicate) : 스트림의 모든 요소가 Predicate를 만족하면 true를 반환
  • boolean anyMatch(Predicate<? super T> predicate) : 스트림의 요소 중 하나라도 Predicate를 만족하면 true를 반환
  • boolean noneMatch(Predicate<? super T> predicate) : 스트림의 요소 중 하나라도 Predicate를 만족하지 않으면 true를 반환

집계

  • 기본 집계 메소드

    • 기본형 스트림의 통계 : count(), sum(), average(), min(), max()
    • T 타입 스트림의 통계 : count(), min(), max() (min, max의 경우 Comparator 필요)
  • reduce() 메소드

    • Optional<T> reduce(BinaryOperator<T> accumulator) : accumulator를 수행하고 Optional<T> 타입 반환
    • T reduce(T identity, BinaryOperator<T> accumulator) : identity를 초기값으로 하여, accumulator를 이용해 집계 연산
    • <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) : combiner를 이용해 병렬 스트림 결합
  • java.util.Optional<T>

    • T 타입 객체의 null 여부에 따라 다르게 동작하는 Wrapper 클래스
    • Optional 클래스의 정적 메소드를 이용해 Optional 객체 생성
      • public static <T> Optional<T> of(T value) : value가 null인 경우 NullPointerException을 발생시키는 Wrapping 메소드
      • public static <T> Optional<T> ofNullable(T value) : value가 null인 경우 empty()의 결과를 리턴하는 Wrapping 메소드
      • public static <T> Optional<T> empty() : 값이 비어있는 Optional 객체를 리턴
    • Optional 객체를 처리하는 메소드
      • public T get() : Optional의 값을 리턴하며, null일 경우 NullPointerException 발생
      • public void ifPresent(Consumer<? super T> consumer) : Optional 값이 null이 아닐 경우 consumer를 이용해 소비한다.
      • public T orElse(T other) : Optional의 값이 null일 경우 other를 반환한다.
      • public T orElseGet(Supplier<? extends T> other) : Optional의 값이 null일 경우 Supplier를 통해 공급받은 값을 반환한다.
      • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X : Optional의 값이 null일 경우 exceptionSupplier에서 공급받은 예외를 throw

반복

forEach() 메소드로 스트림 요소를 순차적으로 Consumer<T>를 이용해 소비

  • void forEach(Comsumer<? super T> action) : 스트림의 각 요소를 action으로 소비

조사

첫번째 요소 또는 아무 요소를 조사하는 최종 처리 메소드. 필터링 등으로 인해 스트림에 요소가 남아있는지 확인할 수 있다.

  • Optional<T> findFirst() : 스트림의 첫 요소 또는 empty Optional 객체를 반환
  • Optional<T> findAny() : 스트림의 아무 요소나 가지는 Optional 객체를 반환

수집

필요한 요소를 수집하여 새로운 Collection으로 구성하여 반환하는 메소드

  • collect() 메소드

    • <R, A> R collect(Collector<? super T, A, R> collector) : collector를 이용해 새로운 Collection R에 담아 반환

      • Collectors의 정적 메소드: toList(), toSet(), toCollection(), toMap(), toConcurrentMap()
    • <R, A> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) : supplier를 통해 공급된 컨테이너 R에 accumulator를 이용해 T값을 저장. 병렬처리 스트림에 사용될 경우 combiner를 이용해 스레드별 컨테이너 R을 통합

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};
      List<String> list = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toList()); // ArrayList
      // .collect(Collectors.toCollection(LinkedList::new))
      System.out.println(list.getClass().getName() + ":" + list);


      Set<String> set = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toSet()); // HashSet
      // .collect(Collectors.toCollection(HashSet::new))
      System.out.println(set.getClass().getName() + ":" + set);

      Map<String, Integer> map = Arrays.stream(array)
      .filter(s -> s.length() >= 3)
      .collect(Collectors.toMap(s -> s, String::length)); // HashMap
      // .collect(Collectors.toCollection(s -> s, String::length, (oldVal, newVal) -> newVal, TreeMap::new))
      System.out.println(map.getClass().getName() + map);
  • Collectors의 정적 메소드를 이용한 그룹화와 분리

    • public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) : classifier를 key값으로, 해당하는 값의 목록을 List인 value로 가지는 Map으로 스트림을 수집하는 Collector를 반환
      • public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) : List 대신 downstream collector로 수집
    • public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) : predicate 결과를 key로, 해당하는 값의 목록을 List value로 가지는 Map으로 스트림을 수집하는 Collector를 반환
      • public static <T, A, D> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)) : List 대신 downstream collector로 수집
    1
    2
    3
    4
    5
    6
    7
    8
    9
    String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};

    Map<Character, List<String>> map1 = Arrays.stream(array)
    .collect(Collectors.groupingBy(s -> s.charAt(0)));
    System.out.println(map1);

    Map<Boolean, List<String>> map2 = Arrays.stream(array)
    .collect(Collectors.partitioningBy(s -> s.length() >= 3));
    System.out.println(map2);
  • 집계를 위한 Collector

    • Downstream collector로 집계를 위한 Collector를 사용할 경우 유용하다.
    • counting(), summingP(), averagingP(), maxBy(), minBy(), reducing()
    1
    2
    3
    4
    5
    6
    String[] array = {"Java", "Is", "Fun", "Isn't", "It", "?"};

    Map<Character, Long> map = Arrays.stream(array)
    .collect(Collectors.groupingBy(s -> s.charAt(0),
    Collectors.counting()));
    System.out.println(map);

병렬 스트림

  • 병렬 스트림의 생성

    • stream() 대신 parallelStream()으로 변경
    • stream 생성 후 parallel()으로 병렬화
  • combiner를 이용해 병렬 스트림으로 생성된 컬렉션을 결합

    • BiConsumer<T, K> combiner : T 객체에 K 객체를 결합

Comment and share

람다식 (Lambda Expression)

람다식이란

  • Java 1.8에서 추가된 함수형 프로그래밍 기법
  • 객체지향 프로그래밍과 다르게, 비즈니스 로직만을 빠르게 구현하는 특징
  • 객체지향 언어인 Java에서 메소드를 함수처럼 사용하는 형식

람다식의 예

배열의 정렬

  • 기본 정렬 방식을 이용한 정렬

    1
    2
    3
    4
    String [] strings = {"fast", "campus", "java", "backend", "school"};
    System.out.println(Arrays.toString(strings));
    Arrays.sort(strings);
    System.out.println(Arrays.toString(strings));
    1
    2
    3
    public int compare(String o1, String o2) {
    return o1.compareTo(o2);
    }
  • 익명 내부 클래스를 이용한 정렬 방식 변경

    1
    2
    3
    4
    5
    6
    Arrays.sort(strings, new Comparator<String>() { // 객체를 생성하여 전달
    @Override
    public int compare(String o1, String o2) {
    return o1.compareTo(o2) * -1; // 내림차순
    }
    });
  • 람다식을 이용한 정렬 방식의 변경

    1
    Arrays.sort(strings, (o1, o2) -> {return o1.compareTo(o2) * -1;});
    1
    2
    3
    4
    Comparator<String> comp = (o1, o2) -> {
    return o1.compareTo(o2) * -1;
    };
    Arrays.sort(strings, comp);
  • 함수형 인터페이스 (Functional Interface)

    • 추상 메소드가 단 하나 존재하는지 검사

      1
      2
      3
      4
      5
      @FunctionalInterface
      public interface Comparator<T> {
      int compare(T o1, T o2);
      ...
      }

람다식의 형식

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(String x) -> { System.out.println(x); }

(x) -> { System.out.println(x); }

x -> System.out.println(x)

() -> System.out.println("x"); // () 생략 불가능

(x) -> {
System.out.println(x);
return x;
}

(x) -> "x: " + x

// x -> "x :" + x // () 생략 불가능

람다식의 변수 참조

  • 익명 내부 클래스와 동일한 규칙으로 변수 참조

  • 문법적으로 this의 사용법만 다름

    • 익명의 내부 클래스와 달리 외부 클래스를 참조
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @FunctionalInterface
    interface FunctionalInterface {
    String method();
    }

    class Main {
    void functionalMethod(FunctionalInterface obj) {
    System.out.println(obj.method());
    }

    public static void main(String[] args) {
    functionalMethod(()-> {
    System.out.println("this: " + this);
    System.out.println("OuterClass.this: " + Main.this);
    return "Lambda expression used."
    });

    functionalMethod(new FunctionalInterface() {
    @Override
    String method() {
    System.out.println("this: " + this);
    System.out.println("OuterClass.this: " + Main.this);
    return "Anonymous inner class used."
    });
    }

    }

표준 함수형 인터페이스

  • 자주 사용되는 함수형 인터페이스를 정의해 둔 API
  • Consumer, Supplier, Function, Operation, Predicate 계열이 있다.
계열 입력 출력 메소드 설명
Consumer O X void accept(T) 입력을 소비
Supplier X O T get() 출력을 공급
Function O O T apply(R) 입력 -> 출력 함수 매핑
Operation O O T apply(T) 입력을 연산하여 동일 타입의 출력으로 리턴
Predicate O boolean boolean test(T) 입력을 판단

표준 함수형 인터페이스의 종류

Consumer 계열

인터페이스 메소드
Consumer<T> void accept(T t)
BiConsumer<T, U> void accept(T t, U u)
IntConsumer void accept(int value)
LongConsumer void accept(long value)
DoubleConsumer void accept(double value)
ObjIntConsumer<T> void accept(T t, int value)
ObjLongConsumer<T> void accept(T t, long value)
ObjDoubleConsumer<T> void accept(T t, double value)

Supplier 계열

인터페이스 메소드
Supplier<T> T get()
BooleanSupplier boolean getAsBoolean()
IntSupplier int getAsInt()
LongSupplier long getAsLong()
DoubleSupplier double getAsDouble()

Function 계열

인터페이스 메소드
Function<T, R> R apply(T t)
BiFunction<T, U, R> R apply(T t, U u)
PFunction<R> R apply(p value)
PtoQFunction q applyAsQ(p value)
ToPFunction<T> p applyAsP(T t)
ToPBiFunction<T, U> p applyAsP(T t, U u)
1
2
P, Q : Int, Long, Double
p, q : int, long, double

Operator 계열

인터페이스 메소드
UnaryOperator<T> T apply(T t)
BinaryOperator<T> T apply(T t1, T t2)
IntUnaryOperator int applyAsInt(int value)
LongUnaryOperator long applyAsLong(long value)
DoubleUnaryOperator double applyAsDouble(double value)
IntBinaryOperator int applyAsInt(int value1, int value2)
LongBinaryOperator long applyAsLong(long value, long value2)
DoubleBinaryOperator double applyAsDouble(double value, double value2)

Predicate 계열

인터페이스 메소드
Predicate<T> boolean test(T t)
BiPredicate<T, U> boolean test(T t, U u)
IntPredicate boolean test(int value)
LongPredicate boolean test(long value)
DoublePredicate boolean test(double value)

표준 함수형 인터페이스의 메소드

andThen(), compose()

  • 두 개 이상의 함수형 인터페이스를 연결하기 위해 사용

    • A.andThen(B): A를 먼저 실행하고 B를 실행. Consumer, Function, Operator 계열 지원
    1
    2
    3
    Function<String, String> funcOne = x -> "str: " + x;
    Function<String, String> funcTwo = x -> "{" + x + "}";
    Function<String, String> andThen = funcOne.andThen(funcTwo); // {str: x}
    • A.compose(B): B를 먼저 실행하고 A를 실행. Function, Operator 계열 지원
    1
    2
    3
    IntUnaryOperator multTwo = x -> x * 2;
    IntUnaryOperator addTen = x -> x + 10;
    IntUnaryOperator multTwo.compose(addTen); // (x + 10) * 2

and(), or(), negate(), isEqual()

  • Predicate 계열의 기본 메소드

    • and(), or(), negate()
    • 각각 &&, ||, !의 동작을 한다.
    1
    2
    3
    4
    DoublePredicate predOne = x -> x > 0.5;
    DoublePredicate predTwo = x -> x < 0.0;
    DoublePredicate predThree = predOne.or(predTwo);
    DoublePredicate predFour = predThree.negate();
  • Predicate 계열의 클래스 메소드

    • isEqual()
    1
    Predicate<String> isEqualToString = Predicate.isEqual("String");

minBy(), maxBy()

  • BinaryOperator 클래스의 클래스 메소드

    • Comparator<T>를 파라미터로 받아 최소값/최대값을 구하는 BinaryOperator<T>를 리턴
    1
    2
    3
    4
    5
    6
    7
    BinaryOperator<String> minBy = BinaryOperator.minBy((o1, o2) -> {
    return len(o1) > len(o2) ? 1 : -1;
    });

    BinaryOperator<Integer> maxBy = BinaryOperator.maxBy((val1, val2) -> {
    return val1.compareTo(val2);
    });

람다식에 메소드/생성자 사용

  • 이미 구현된 메소드가 있는 경우, 다양한 방식으로 람다식을 대체 가능

ClassName::instanceMethod

  • 첫번째 파라미터를 객체로, 두번째 파라미터를 메소드 입력으로 사용

    1
    2
    String[] strings = { "A", "B", "D", "C" };
    Arrays.sort(strings, String::compareTo);

ClassName::classMethod

  • 클래스 메소드의 입력으로 모든 파라미터가 사용됨

    1
    Function<String, Integer> parser = Integer::parseInt;

instance::instanceMethod

  • 주어진 객체의 메소드를 호출

    1
    2
    3
    String string = "StringA";
    Predicate<String> pred = string::equals;
    System.out.println(pred.apply("StringA"));

ClassName::new

  • 생성자를 이용하여 객체를 생성하는 람다식

    1
    2
    IntFunction<String> func = String::new;
    String string = func.apply(10);

ClassName[]::new

  • 배열을 생성하는 람다식

    1
    2
    IntFunction<String[]> func = String[]::new;
    String [] strings = func.apply(100);

Comment and share

내부 클래스 (Inner Classes)

내부 클래스란

  • 클래스 내부에 선언하는 클래스로 중첩 클래스(Nested Class)라고도 부름
  • HAS-A 관계에 있는 클래스가 해당 클래스에서만 사용될 경우 주로 사용

내부 클래스의 종류

  • 클래스 영역에 선언
    • 인스턴스 내부 클래스: 외부 클래스의 멤버 변수처럼 사용 가능
    • 클래스 내부 클래스: static이 붙은 정적인 내부 클래스
  • 로컬 영역에 선언
    • 로컬 내부 클래스: 선언된 영역의 Scope 내에서 사용 가능
    • 익명 내부 클래스: 객체를 일회성으로 생성하기 위한 이름이 없는 클래스

다양한 내부 클래스

인스턴스 내부 클래스 (Instance Inner Class)

  • 클래스 영역에 static 키워드 없이 선언된 클래스

  • 외부 클래스의 private을 포함한 모든 멤버에 접근 가능

  • 외부 클래스 객체를 통해서만 생성 가능

  • static 멤버 변수는 사용할 수 없으나, static final은 사용 가능

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class Outer {
    class InstanceInner {
    int innerMemberVar = 1;
    //static int staticMemberVar = 1;
    static final int CONSTANT_VAR = 10;

    void innerMethod() {
    System.out.println(innerMemberVar);
    System.out.println(outerMemberVar);
    }
    }

    private int outerMemberVar = 2;

    void outerMethod() {
    IstanceInner obj = new InstanceInner();
    obj.innerMethod();
    }

    public static void main(String[] args) {
    Outer outer = new Outer();
    InstanceInner inner = outer.new InstanceInner();
    inner.innerMethod();
    }

    }
  • 외부 클래스의 멤버 변수와 이름이 겹치는 경우 this 활용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Outer {
    class InstanceInner {
    int var = 1;

    void innerMethod() {
    int var = 0;
    System.out.println(var);// 0
    System.out.println(this.var);// 1
    System.out.println(Outer.this.var);// 2
    System.out.println(Outer.y); // 3 static variable
    }
    }

    private int var = 2;
    private static int y = 3;

    public static void main(String[] args) {
    Outer outer = new Outer();
    InstanceInner inner = outer.new InstanceInner();
    inner.innerMethod();
    }

    }

클래스 내부 클래스 (Class Inner Class)

  • 클래스 영역에 static 키워드와 함께 선언된 내부 클래스

  • 외부 클래스 객체가 없어도 생성 가능

  • 외부 클래스의 private을 포함한 모든 멤버에 접근 가능

  • static 멤버 변수를 가질 수 있음

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Outer {
    static class ClassInner {
    int innerVar = 1;
    static int staticInnerVar = 100;

    void innerMethod() {
    Outer outer = new Outer();
    System.out.println(outer.outerVar);
    System.out.println(innerVar);
    }
    }

    private int outerVar = 2;

    void outerMethod() {
    ClassInner inner = new ClassInner();
    inner.innerMethod();
    }

    public static void main(String[] args) {
    ClassInner inner = new ClassInner();
    inner.innerMethod();
    }
    }

로컬 내부 클래스 (Local Inner Class)

  • 클래스 영역이 아닌 로컬 영역에서 선언된 클래스

    • 메소드, 생성자, 초기화 블록의 내부
  • 정적 변수는 가질 수 없으나, static final 변수는 가질 수 있음

  • 로컬 영역의 변수 다음과 같은 사항을 따름

    • Java1.7: final로 선언된 변수에만 접근 가능
    • Java1.8: 모든 변수에 접근 가능하나, final로 간주되어 새로운 값 할당 불가
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void outerMethod() {
    int var = 1; // 메소드 호출 스택

    class LocalInner {
    void innerMethod() {
    System.out.println(var);
    }
    }

    LocalInner inner = new LocalInner(); // 힙 영역
    inner.innerMethod();
    }

익명의 내부 클래스 (Anonymous Inner Class)

  • 로컬 내부 클래스와 동일하나, 이름이 없어 선언 즉시 한 번 사용 가능

  • 추상 클래스나 인터페이스의 구현에 많이 사용

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    interface IFoo {
    void do();
    }

    class AnonymousInnerClassTest {
    static void useFoo(IFoo foo) {
    foo.do();
    }

    public static void main(String[] args) {
    useFoo(new IFoo() {
    @Override
    void do() {
    System.out.println("Do!");
    }
    });
    }
    }

Comment and share

  • page 1 of 1

Yechan Kim

author.bio


author.job