Inner Class, Lambda Expression, Stream

Inner Class

  • 클래스 내부에 구현한 클래스, 주로 외부 클래스 생성자에 내부 클래스를 생성

  • 내부 클래스 유형

종류 구현 위치 사용할 수 있는 외부 클래스 변수 생성 방법
인스턴스 내부 클래스 외부 클래스 멤버 변수와 동일 외부 인스턴스 변수
외부 전역 변수
외부 클래스를 먼저 만든 후 내부 클래스 생성
정적 내부 클래스 외부 클래스 멤버 변수와 동일 외부 전역 변수 외부 클래스와 무관하게 생성
지역 내부 클래스 메소드 내부에 구현 외부 인스턴스 변수
외부 전역 변수
메소드를 호출할 때 생성
익명 내부 클래스 메소드 내부에 구현
변수에 대입하여 직접 구현
외부 인스턴스 변수
외부 전역 변수
메소드를 호출할 때 생성되거나, 인터페이스 타입변수에 대입할 때 new예약어를 사용하여 생성
  • 인스턴스/정적 내부 클래스
class OutClass{

  private int num = 10;
  private static sNum = 20;
  private InClass inClass;

  public OutClass() {
    inClass = new InClass();
  }

  class InClass{ //인스턴스 내부 클래스
    int iNum = 100;
    //static int sInNum = 200; static클래스 아니므로 사용불가

    void inTest() {
      System.out.println(num); //10
      System.out.println(sNum); //20
    }
  }

  public void usingInTest() {
    inClass.inTest();
  }

  static class InStaticClass {
    int inStaticNum = 100;
    static int sInStaticNum = 200;

    void inStaticTest() {
      System.out.println(num); //10
      System.out.println(sNum); //20
      System.out.println(inStaticNum); //100
      System.out.println(sInStaticNum); //200
    }

    static void sTest() { //Inner Static Class 안 Static method
      System.out.println(num); //10
      System.out.println(sNum); //20

      //아래 println은 전부 에러. 인스턴스 생성 후 멤버 변수 사용가능하기 때문에 클래스이름만으로 바로 호출은 안될것.

      // System.out.println(inStaticNum); //100
      // System.out.println(sInStaticNum); //200
    }
  }

}

public class Main {
  psvm{
    OutClass ouclass = new OutClass();
    outClass.usingInTest(); //inTest호출됨

    OutClass.InClass inClass = outClass.new InClass(); //InClass 인스턴스만들기 private아닐 때만 가능

    OutClass.InStaticClass.sTest(); //스태틱메소드 호출

    OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
    sInClass.inStaticTest();
  }
}
Local/Annonymous Inner Class
  • 지역 내부 클래스
    지역 변수와 같이 메소드 내부에서 정의하여 사용하는 클래스,
    메소드 호출이 끝나면 메소드에 사용된 지역변수의 유효성은 사라짐
    메소드 호출 이후에도 사용해야 하는 경우가 있을수 있으므로, 지역 내부 클래스에서 사용하는 메소드의 지역
    변수나 매개 변수는 final로 선언됨.
class Outer {

  int outNum = 100;
  static int sNum = 200;

  Runnable getRunnable(int i) {

    int num = 10; //stack

    class MyRunnable implements Runnable {

      int localNum = 1000; //stack

      @Override
      public void run() {
        //i = 100; error
        //num = 20; error
        System.out.println(i);
        System.out.println(num);
        System.out.println(outNum);
        System.out.println(Outer.sNum);
      }
    }
    return new MyRunnable();
  }
}

i 와 num의 값을 변경하는데에서 error가 나는 이유는 getRunnable()메소드가 호출되는 시점과, MyRunnable 지역 내부 클래스가 생성되는 시점이 다르고, stack메모리에 있는 변수값이 메소드 호출 후에 없어지기 때문이다. 이를 해결하기 위해서는, final로 선언해서 상수화한다. 현재는 final선언 해주지 않아도 컴파일러가 바꿔준다.

class Outer {

  int outNum = 100;
  static int sNum = 200;

  Runnable getRunnable(final int i) {

    final int num = 10; //stack

    class MyRunnable implements Runnable {

      int localNum = 1000; //stack

      @Override
      public void run() {
        i = 100;
        num = 20;
        System.out.println(i);
        System.out.println(num);
        System.out.println(outNum);
        System.out.println(Outer.sNum);
      }
    }
    return new MyRunnable();
  }
}
  • 익명 내부 클래스 위의 MyRunnable클래스를 유심히 보면, 이 클래스명은 Outer안에서만 쓰고 다른데에서는 직접 사용할 일이 전혀 없다. 클래스의 이름이 즉 필요가 없고, 다음과 같이 한다.
class Outer {

  int outNum = 100;
  static int sNum = 200;

  Runnable getRunnable(final int i) {

    final int num = 10; //stack

    return new Runnable(){ //익명 내부 클래스

      int localNum = 1000; //stack

      @Override
      public void run() {
        i = 100;
        num = 20;
        System.out.println(i);
        System.out.println(num);
        System.out.println(outNum);
        System.out.println(Outer.sNum);
      }
    };//익명 내부 클래스 끝나는 곳에 세미콜론 필수
    //객체 return문 삭제
  }

  Runnable runnable = new Runnable() { //클래스의 멤버변수로 접근할 수 있도록 하는법
    @Override
    public void run() {
      System.out.println("runnable class");
    }
  }
}

Lambda Expression

함수형 프로그래밍과 람다식

  • JAVA8 부터 함수형 프로그래밍을 지원하고 있고, 그것을 람다식이라 부른다.
  • 함수의 구현과 호출만으로 프로그래밍이 수행되는 방식
  • 함수형 프로그래밍(FP)이란
    순수함수를 구현하고 호출함으로써, Side Effect 를 주지 않도록 구현하는 방식.
  • 순수함수
    매개변수만을 사용해서 만드는 함수. 함수 외부의 변수를 사용하지 않아 함수가 수행된 후 외부에 영향이 없다.
  • 병렬처리에 용이

람다식 문법

  • 익명 함수 만들기
  • 매개 변수와 매개변수를 이용한 실행문 (매개변수) -> {실행문;}
    (int x, int y) -> {return x + y;}
    (x, y) -> {System.out.println(x);} //매개변수 자료형 생략 가능
    str -> {System.out.prinln(str)} //매개변수가 하나이면 괄호 생략 가능
    (x, y) -> x + y; //return생략, 중괄호 생략
    
  • 함수형 인터페이스로 사용하는 예 ~~~java //interface 선언해놓고, public interface Add { public int add(int x, int y); }

//psvm에서, Add a = (x, y) -> {return x+y;}; //add구현 System.out.println(a.add(2,3)); ~~~

함수형 인터페이스 선언하기

  • 람다식을 선언하기 위한 인터페이스
  • 익명함수와 매개변수만으로 구현되므로 인터페이스는 단 하나의 메소드만 선언해야함(여러개일 시 어떤 메소드 를 구현해야하는지 모르므로)
  • @Functional Interface 어노테이션