🌱Backend/Java

#5. μžλ°”μ˜ Interface

JiwonDev 2021. 7. 1. 10:52

# Abstract Class (좔상 클래슀)

참고둜 클래슀 내뢀에 κ΅¬ν˜„λΆ€κ°€ μ—†κ³ , μ„ μ–Έλ§Œ λ˜μ–΄μžˆλŠ” 것을 Abstract Method(좔상 λ©”μ„œλ“œ) 라고 ν•œλ‹€. 좔상 λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜λŠ” ν΄λž˜μŠ€λŠ” abstract ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ λ°˜λ“œμ‹œ 좔상 클래슀둜 λ§Œλ“€μ–΄μ•Ό ν•œλ‹€. 객체의 μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜μ§€ μ•Šκ²Œ λ°©μ§€ν•˜κΈ° μœ„ν•¨μ΄λ‹€.

public abstract class Animal {
    public abstract String getFood();
}

μž¬λ°ŒλŠ” 점은 μΆ”μƒλ©”μ„œλ“œκ°€ ν•˜λ‚˜λΌλ„ 있으면 λ°˜λ“œμ‹œ ν‘œμ‹œν•΄μ£Όμ–΄μ•Ό ν•˜μ§€λ§Œ, μΆ”μƒλ©”μ„œλ“œκ°€ 없더라도 객체의 μΈμŠ€ν„΄μŠ€ 생성을 λ°©μ§€ν•˜κΈ° μœ„ν•΄ abstract classλ₯Ό μ„ μ–Έ ν•  μˆ˜λ„ μžˆλ‹€. μ΄λŠ” Math 같이 ꡳ이 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€ ν•„μš”κ°€ μ—†λŠ” 클래슀 등에 μ‚¬μš©λœλ‹€.

 


# Interface

μΈν„°νŽ˜μ΄μŠ€λ„ 좔상 클래슀의 일쒅이라고 λ³Ό 수 μžˆλ‹€. λ‹€λ§Œ μ΄λ¦„μ—μ„œ μœ μΆ” ν•  수 μžˆλ“―μ΄, μΈν„°νŽ˜μ΄μŠ€ λ‚΄λΆ€μ—λŠ” 좔상 λ©”μ„œλ“œ(public abstract)와 μƒμˆ˜(static final)만 μ‚¬μš© ν•  수 μžˆλ‹€.

interface MyInterface{
      public static final int MY_VALUE = 10;
      int MT_VALUE2 = 10; // μΈν„°νŽ˜μ΄μŠ€μ—μ„œλŠ” μžλ™μœΌλ‘œ μƒμˆ˜ν™” (static final) λœλ‹€.
      public abstract myMethod();

      // μΈν„°νŽ˜μ΄μŠ€μ—μ„œλŠ” abstract ν‚€μ›Œλ“œλ₯Ό μƒλž΅ν•΄λ„ μ „λΆ€ public abstract둜 κ°„μ£Όν•œλ‹€.
      // μ•„λž˜ 3κ°œλŠ” μ „λΆ€ public abstract 이닀.
      public abstract myMethod1();
      public myMethod2() ;
      myMethod3() ;
}

 


# Default Method

λ‹€λ§Œ κΈ°μ‘΄ μžλ°”μ—μ„œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•¨μ— μžˆμ–΄, μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 좔상 λ©”μ„œλ“œλ„ μ „λΆ€ κ΅¬ν˜„ν•΄μ£Όμ–΄μ•Ό μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 수 μžˆκΈ°μ— λΆˆνŽΈν•¨μ΄ λ§Žμ•˜λ‹€. κ·Έλž˜μ„œ Java8 λΆ€ν„°λŠ” default ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ κΈ°λ³Έ κ΅¬ν˜„ 값을 적을 수 있게 ν•΄μ£Όμ—ˆλ‹€.

package com.company;

public interface Foo {
    void printName(); // μΆ”μƒλ©”μ„œλ“œ 1
    String getName(); // μΆ”μƒλ©”μ„œλ“œ 2

    // μ΄λŸ°μ‹μœΌλ‘œ default ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ 기본값을 적을 수 μžˆλ‹€.
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }
}

 

ν•˜μ§€λ§Œ defalut λ©”μ„œλ“œλ₯Ό λ„ˆλ¬΄ λ―Ώκ³  μ‚¬μš©ν•˜κΈ°μ—λŠ” μ½”λ“œμ˜ μ•ˆμ „μ„±μ„ 보μž₯ν•  수 없기에 μΈν„°νŽ˜μ΄μŠ€μ˜ JavaDoc을 잘 읽어보고 ν•„μš”ν•˜λ‹€λ©΄ κΈ°λ³Έ λ©”μ„œλ“œλ₯Ό @Overrideν•΄μ„œ μ‚¬μš©ν•˜λ„λ‘ ν•˜μž.

public interface Foo {
    /**
     * @implSpec
     * 이 κ΅¬ν˜„μ²΄λŠ” getName()으둜 κ°€μ Έμ˜¨ λ¬Έμžμ—΄μ„ λŒ€λ¬Έμžλ‘œ λ°”κΏ” 좜λ ₯ν•œλ‹€.
     */
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }
}

 

참고둜 Objectμ—μ„œ μ œκ³΅ν•˜λŠ” λ©”μ„œλ“œ (equal, toString)λŠ” μΈν„°νŽ˜μ΄μŠ€μ—μ„œ default둜 μ •μ˜ ν•  수 μ—†λ‹€. μ‚¬μš©ν• λ €λ©΄ λ°˜λ“œμ‹œ κ΅¬ν˜„μ²΄κ°€ μž¬μ •μ˜ λ˜μ–΄μ•Ό ν•œλ‹€.

public interface Foo {
    void printName(); // μΆ”μƒλ©”μ„œλ“œ 1
    String getName(); // μΆ”μƒλ©”μ„œλ“œ 2
    
    String toString(); // Object λ©”μ„œλ“œλ„ μΆ”μƒλ©”μ„œλ“œλ‘œ μ •μ˜λŠ” κ°€λŠ₯.
//  default String toString(); // 컴파일 μ—λŸ¬!! default μ‚¬μš©μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.
}

# μΈν„°νŽ˜μ΄μŠ€ 상속

μΈν„°νŽ˜μ΄μŠ€λ„ μƒμ†ν•΄μ„œ μ‚¬μš© ν•  수 μžˆλ‹€. λΆ€λͺ¨μ—μ„œ Default둜 κ΅¬ν˜„ λ˜μ–΄μžˆλŠ” 뢀뢄을 μΆ”μƒλ©”μ„œλ“œλ‘œ λ³€κ²½ν•  μˆ˜λ„ μžˆλ‹€.

참고둜 μžλ°”μ—μ„œλŠ” μ—¬λŸ¬ 객체듀을 λ™μ‹œμ— 상속 ν•  수 μžˆκΈ°μ— 닀쀑상속 쀑볡 문제(Diamond Problem)κ°€ μžˆκΈ΄ν•œλ°, 이 경우 컴파일 μ—λŸ¬κ°€ λœ¨λ‹ˆ 직접 ν•˜λ‚˜ν•˜λ‚˜ @Override ν•΄μ£Όλ©΄ λœλ‹€. λ‹€λ§Œ μ‹€μ œ κ°œλ°œμ—μ„œ μ΄λŸ°μ‹μ˜ 닀쀑 상속을 μ‚¬μš©ν•˜λŠ” κ²½μš°κ°€ 거의 μ—†λ‹€.

public interface Foo {
    String getName();
    default void printName();{
    	System.out.println("Hello");
    }
}


public interface Bar extends Foo{
    void printName(); // Foo 의 defaultλ©”μ„œλ“œλ₯Ό μ—†μ• μ£Όμ—ˆλ‹€.
    void newMethod();
}

# Java8에 μΆ”κ°€λœ κΈ°λ³Έ λ©”μ„œλ“œ, μΈν„°νŽ˜μ΄μŠ€

μœ„μ™€ 같이 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ— μ‚¬μš©ν•˜κΈ° μ’‹κ²Œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•΄μ€ŒμœΌλ‘œμ„œ μž¬λ°ŒλŠ” λ©”μ„œλ“œλ“€μ΄ 많이 μΆ”κ°€λ˜μ—ˆλ‹€. 이 κΈ€μ—μ„œλŠ” κ°„λ‹¨ν•˜κ²Œ μ‚΄νŽ΄λ§Œ 보고 λ‹€μŒ 글에 μžμ„Ένžˆ μ„€λͺ…ν•˜λ„λ‘ ν•˜κ² λ‹€.

 

Iterable의 κΈ°λ³Έ λ©”μ†Œλ“œ

  • forEach()
  • spliterator()
import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;

public class Main {
    public static void main(String[] args) {
        List<String> name = Arrays.asList("Hi", "Bye", "Ho", "AB");
        name.forEach(System.out::println); // 각각의 μš”μ†Œλ₯Ό 좜λ ₯

        // split + iterator. 큰 배열을 반으둜 λ‚˜λˆ  각각 iterλ₯Ό 돌릴 수 μžˆλ‹€.
        Spliterator<String> spliterator1 = name.spliterator();
        Spliterator<String> spliterator2 = spliterator1.trySplit(); // μžλ™μœΌλ‘œ λ‚˜λˆ μ€€λ‹€.
        
        while(spliterator1.tryAdvance(System.out::println)); // "Hi", "Bye"
        while(spliterator2.tryAdvance(System.out::println)); // "Ho", "AB"
    }
}

 

Collection의 κΈ°λ³Έ λ©”μ†Œλ“œ

  • stream() / parallelStream()
  • removeIf(Predicate)
  • spliterator()
public class Main {
    public static void main(String[] args) {
        List<String> name = Arrays.asList("KHi", "Bye", "KHo", "AB");

        long nStartsWithK = name.stream().map(String::toUpperCase)
                .filter(str -> str.startsWith("K"))
                .count();
        System.out.println(nStartsWithK); // 2

        List<String> names = name.stream().map(String::toUpperCase)
                .filter(str -> str.startsWith("K"))
                .collect(Collectors.toList());
        System.out.println(names); // ["KHi", "KHo"]
    }
}

 

Comparator의 κΈ°λ³Έ λ©”μ†Œλ“œ 및 μŠ€νƒœν‹± λ©”μ†Œλ“œ

  • reversed()
  • thenComparing()
  • static reverseOrder() / naturalOrder()
  • static nullsFirst() / nullsLast()
  • static comparing()

 

+ Java9의 Private Method

μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€λ©΄μ„œ μ‚¬μš©μ„ νŽΈν•˜κ²Œ ν•˜κΈ°μœ„ν•΄ Java8에 default λ©”μ„œλ“œ κΈ°λŠ₯을 μΆ”κ°€ν•˜μ˜€λ‹€. 그런데 μ‚¬μš©ν•˜λ‹€λ³΄λ©΄ default λ©”μ„œλ“œκ°€ λ‹¨μˆœνžˆ μ‚¬μš©μ„ νŽΈν•˜κ²Œ ν•˜κΈ°μœ„ν•¨μ΄ μ•„λ‹ˆλΌ, κ³ μ •λœ κΈ°λ³Έ 값을 주고싢은 κ²½μš°κ°€ μžˆλŠ”λ° 그럴 λ•Œλ₯Ό μœ„ν•΄μ„œ Java9λΆ€ν„° private MethodλΌλŠ” κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€.

Private λ©”μ„œλ“œλŠ” default λ©”μ„œλ“œμ™€ λΉ„μŠ·ν•˜λ‚˜, μΈν„°νŽ˜μ΄μŠ€λ₯Ό 상속 λ°›μ•„μ„œ λ‚΄μš©μ„ μˆ˜μ •ν•˜μ§€ λͺ»ν•˜κ²Œ λ§‰ν˜€μžˆλ‹€.

public interface Boo {
    /**
     * @implSpec 이 λ©”μ†Œλ“œλŠ” μ˜€λ²„λΌμ΄λ“œ ν•˜κ±°λ‚˜, μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•  수 μ—†μŠ΅λ‹ˆλ‹€.  
     * @return "Bye"
     */
    private String printBye(){ // default와 λ™μΌν•œ κΈ°λŠ₯. ν•˜μ§€λ§Œ λ³€κ²½ λΆˆκ°€λŠ₯
        return "Bye";
    }
    default void knockDoor(){
        System.out.println("Ok.. " + printBye());
    }
}
public class Main implements Boo{
    @Override //Error -> method does not override or implement a method from a supertype
    public String printBye(){
        return "Bye";
    }
}