内部クラスとラムダ式の勉強メモ


苦手な内部クラスとラムダ式の勉強メモです。。

内部クラス

クラスの中に、クラスが作れる

//外部クラス
class Outer{
    //内部クラス
    class Inner{
        //
    }
}

クラスのメソッドの中に、クラスが作れる

メソッドの中に定義した内部クラスの生成は、このメソッド内でしか、出来ない。

class Outer{
    void test() {
        class Inner{
        }
        Inner in = new Inner();
    }
}

内部クラスは、外部クラスのprivateなインスタンス変数にアクセスできる。

class Outer{
    private String msg = "hoge";

    void test() {
        class Inner{
            void test() {
                System.out.println(msg);
            }
        }
        Inner in = new Inner();
        in.test();
    }
}

public class MultiThreadEx {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.test();
    }
}

匿名クラス(AnonymousClass)

内部クラスの仲間。クラス名がないものを匿名クラスという。

準備:

interface Hello{
    public void hello();
}
class Greeting {
    static void greet(Hello s) {
        s.hello();
    }
}

一般的な例:

class Person implements Hello{
    @Override
    public void hello() {
        // TODO 自動生成されたメソッド・スタブ
        System.out.println("はよ");
    }
}
public class SampleProgram{
    public static void main(String[] args)  {
        Person p = new Person();
        Greeting.greet(p);

    }
}

内部クラスの例:

//内部クラスの書き方
public class SampleProgram{
    public static void main(String[] args) {
        class Person implements Hello{

            @Override
            public void hello() {
                // TODO 自動生成されたメソッド・スタブ
                System.out.println("はに");
            }
        }
        Person p = new Person();
        Greeting.greet(p);
        //上記2行を1行にした書き方
        Greeting.greet(new Person());
    }
}

匿名クラスの例:
メソッドの引数を指定する場所で、クラス宣言を行うと、クラス名を付ける必要がなくなる。
うーん、、、慣れないなぁ。。。

public class SampleProgram{
    public static void main(String[] args) {
        Greeting.greet(new Hello() {

            @Override
            public void hello() {
                // TODO 自動生成されたメソッド・スタブ
                System.out.println("ねむい");

            }
        });
    }
}

ラムダ式

関数型インターフェースを実装したクラスの宣言を、ラムダ式のルール?に従って
コードを省略する書き方(?)

(引数列) -> {処理内容}

関数型インターフェースとは

抽象メソッドを1つしか持たないインターフェースのこと。
2つ以上のメソッドがあるとダメらしい。

試しに、メソッドを追加したら

The target type of this expression must be a functional interface
//この式のターゲット型は、関数インタフェースでなければなりません
型 Greeting のメソッド greet(Hello) は引数 (() -> {}) に適用できません

とコンパイルエラーが表示された。

匿名クラスで作成した処理をラムダ式に書き換えると

public class SampleProgram{
    public static void main(String[] args) {
        Greeting.greet( () -> { System.out.println("おなかすいた"); } );
    }
}

ルール

  • 引数列の型は省略できる
  • 引数が1つだけの場合は、引数を囲む () を省略できる
  • 処理の中身に命令文が1つだけの場合、処理を囲む {} とreturenキーワード、セミコロン(;)を省略できる
//修正前:
Greeting.greet( () -> { System.out.println("おなかすいた"); } );

//修正後:
Greeting.greet( () -> System.out.println("おなかすいた"));

ラムダ式を使ってループ文を作ろう

import java.util.ArrayList;
import java.util.List;

class Animal{
    private String type ;
    private String name;

    Animal(String t, String n){
        this.type = t;
        this.name = n;
    }

    public void showAnimal() {
        System.out.println(this.type+":"+this.name);;
    }
}

public class SampleProgram{
    public static void main(String[] args) {
        List<Animal> list = new ArrayList<Animal>();

        list.add(new Animal("ねこ","たま"));
        list.add(new Animal("インコ", "ピーコ"));
        list.add(new Animal("いぬ","ぽち"));

        //ラムダ式
        list.forEach((Animal a) ->{ a.showAnimal();});
        //ラムダ式の省略形
        list.forEach(a -> a.showAnimal());
    }
}