Java8のラムダ式とかを試すついでにNetBeansの環境設定方法とかもメモ

Java8 の「ラムダ式」・「関数インターフェース」あたりを試すついでに NetBeans の環境設定方法とかもメモする。

#環境
##OS
Windows7 64bit

##Java
1.8.0-ea-b118

##NetBeans
7.4（Java8 に対応してるのは 7.4 から）

#準備
##NetBeans のインストール
[NetBeans IDE ダウンロード](https://netbeans.org/downloads/index.html) ここから NetBeans のインストーラをダウンロードする。

ダウンロードした exe を実行して、インストーラに従ってインストール。

##JDK8 のインストール
[JDK8 Early Access Releases Project Kenai](https://jdk8.java.net/download.html) ここから exe をダウンロード。

ダウンロードした exe を実行して、インストーラに従ってインストール。

#NetBeans のセットアップ
##カラースキームの変更
エディタの色は重要です。少なくとも、デフォルトの白背景は発狂しそうになるので暗い色に変更する。

- [NetBeans Themes: Color Schemes of the NetBeans IDE](http://netbeansthemes.com/)

ここに色々なカラースキームが上げられている。
この中で、 [Avanzzzi v3](http://netbeansthemes.com/avanzzzi-v3/) か [Icarus](http://netbeansthemes.com/icarus/) あたりが個人的には良さげだった。

zip をダウンロードしたら、以下の手順で NetBeans に適用する。

- [ツール] → [オプション] → [フォントと色] → [インポート] をクリック
- ダウンロードしていた zip ファイルを選択
- [使用可能なオプション] で [すべて] にチェックを入れて [OK] をクリック

NetBeans が再起動したら、カラーテーマが適用される。

##空白文字の表示
デフォルトだと空白文字が表示されず発狂しそうになる。
なので、見えるようにする。

[表示] → [表示不可能な文字を表示] を選択してチェックを入れる。

##フォントの変更
デフォルトの英字フォントは見づらくて発狂しそうになるので Consolas に切り替える。
しかし、 Consolas は日本語文字に対応してないので、単純にフォントを Consolas に変えただけだと日本語が表示できなくなってしまう。

なので、 Java のフォント設定を変更し、 Monospaced を選択したら英字フォントが Consolas で、日本語フォントは MS ゴシックで表示されるようにする。

以下のサイトが参考になりました。

- [[NetBeans]Consolasフォントを使う | さまくた-samakuta](http://wp.endo.jp.net/?p=215)

```properties:fontconfig.properties（変更前）
# monospaced のフォント設定部分
monospaced.plain.alphabetic=Courier New
monospaced.bold.alphabetic=Courier New Bold
monospaced.italic.alphabetic=Courier New Italic
monospaced.bolditalic.alphabetic=Courier New Bold Italic

# フォントの優先順序設定部分
sequence.monospaced.windows-31j=japanese,alphabetic,dingbats,symbol
```

```properties:fontconfig.properties（変更後）
# monospaced のフォント設定部分
monospaced.plain.alphabetic=Consolas
monospaced.bold.alphabetic=Consolas Bold
monospaced.italic.alphabetic=Consolas Italic
monospaced.bolditalic.alphabetic=Consolas Bold Italic

# フォントの優先順序設定部分
sequence.monospaced.windows-31j=alphabetic,japanese,dingbats,symbol

# Consolas の設定追記
filename.Consolas=CONSOLA.TTF
filename.Consolas_Bold=CONSOLAB.TTF
filename.Consolas_Italic=CONSOLAI.TTF
filename.Consolas_Bold_Italic=CONSOLAZ.TTF
```

#NetBeans のショートカットとか
Eclipse でよく使っている機能が、 NetBeans ではどうすればいいのかをまとめる。

##基本操作
|ショートカット・操作         |機能                                |Eclipse の場合               |
|:----------------------------|:-----------------------------------|:----------------------------|
|`Ctrl + e`                   |選択行削除                          |`Ctrl + d`                   |
|`Ctrl + Shift + c`           |選択行コメントアウト                |同じ                         |
|`Ctrl + Space`               |入力補完                            |同じ                         |
|`Ctrl + Shift + i`           |インポート文の修正                  |`Ctrl + Shift + o`           |
|`Ctrl + クリック`            |クリックしたメソッド（クラス）に移動|同じ                         |
|`Ctrl + Shift + テンキーの -`|全コードブロックの縮小              |`Ctrl + Shift + テンキーの /`|
|`Ctrl + Shift + テンキーの +`|全コードブロックの展開              |`Ctrl + Shift + テンキーの *`|
|`Ctrl + w`                   |現在開いているエディタを閉じる      |同じ                         |
|`F6`                         |プロジェクトを実行                  |`Ctrl + F11`                 |
|`Ctrl + F5`                  |プロジェクトをデバッグ実行          |`F11`                        |
|`Shift + F11`                |クリーンアップしてからビルド        |デフォルトは無し？           |
|`Ctrl + r`                   |リファクタリング                    |`Shfit + Alt + r`            |

##デバッグ中の操作
|ショートカット・操作|機能              |Eclipse の場合|
|:-------------------|:-----------------|:-------------
|`F8`                |ステップ・オーバー|`F6`          |
|`F7`                |ステップ・イン    |`F5`          |
|`F5`                |再開              |`F8`          |

##テンプレート
|キーワード|生成されるコード        |Eclipse の場合|
|:---------|:-----------------------|:-------------|
|`sout`    |`System.out.println("")`|`sysout`      |

#NetBeans で Java8 を使えるようにする
##Java プラットフォームに Java8 を追加する
[ツール] → [Javaプラットフォーム] を選択。

[Java プラットフォーム・マネージャ] が開くので、 [プラットフォームの追加] を選択。
先ほどインストールしておいた Java8 の JDK フォルダを選択して [次へ] → [終了]。

##プロジェクトで使用する JDK を Java8 にする
プロジェクトを右クリックして、 [プロパティ] を選択。

[ライブラリ] の [Java プラットフォーム] で先ほど追加した [JDK1.8] を選択する。

![JavaプラットフォームでJDK1.8を選択.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/35698863-c7eb-899c-d811-35e639eca023.jpeg)

[ソース] の [ソース/バイナリ形式] で [JDK8] を選択する。

![ソースバイナリ形式でJDK8を選択.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/92161735-b093-d580-2283-1a502387a589.jpeg)

これで Java8 でのプログラミングができるようになる。

#ラムダ式を試す
##基本
```java:ラムダ式の基本
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        MyInterface lambda = str -> "Hello " + str + " !!";
        
        System.out.println(lambda.method("Lambda"));
    }
    
    private static interface MyInterface {
        String method(String str);
    }
}
```

```text:実行結果
Hello Lamda !!
```

- 抽象メソッドを１つだけ持つインターフェースには、ラムダ式を代入できる。
- ラムダ式は、 `(引数) -> 処理;` と記述する。
- `引数` が１つの場合は `( )` を省略できる。
- ラムダ式が単一行の場合は、 `処理` を評価した結果が return される。
- `引数` には型を記述することもできるが、省略しても型推論してくれる。

##引数なし
```java:引数なしのラムダ式
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        MyInterface lambda = () -> "引数なし";
        
        System.out.println(lambda.method());
    }
    
    private static interface MyInterface {
        String method();
    }
}
```

- `()` は省略できない。

##引数が複数
```java:引数が複数ある場合のラムダ式
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        MyInterface lambda = (i, str) -> String.format("i=%d, str=%s", i, str);
        
        System.out.println(lambda.method(10, "string"));
    }
    
    private static interface MyInterface {
        String method(int i, String str);
    }
}
```

```text:実行結果
i=10, str=string
```

##複数行のラムダ式
```java:複数行のラムダ式
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        MyInterface lambda = i -> {
            if (i % 2 == 0) {
                return "偶数";
            } else {
                return "奇数";
            }
        };
        
        System.out.println(lambda.method(11));
    }
    
    private static interface MyInterface {
        String method(int i);
    }
}
```

```text:実行結果
奇数
```

- ラムダ式内が複数行に渡る場合は `{ }` で `処理` を括る。
- 複数行の場合は `return` が必須になる（戻り値が `void` なら不要）。

##ラムダ式の外の変数は final でなくても参照できる
```java:finalじゃなくても参照可能
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        String str = "not final";
        
        MyInterface lambda = () -> System.out.println(str);
        lambda.method();
    }
    
    private static interface MyInterface {
        void method();
    }
}
```

```text:実行結果
not final
```

- ラムダ式の外で宣言されている変数は、 `final` 宣言されていなくても参照できる。

##でも外部の変数は事実上のfinalじゃないとコンパイルエラー
```java:ラムダ式内で参照されている変数は事実上のfinal
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        String str = "not final";
        
        MyInterface lambda = () -> {
            str = "上書き不可";  // コンパイルエラーになる
            System.out.println(str);
        };
        lambda.method();
    }
    
    private static interface MyInterface {
        void method();
    }
}
```

- ラムダ式外で宣言されていて、ラムダ式内で参照されている変数は __事実上のfinal__ である必要がある。
- `str` はラムダ式外で宣言されており、かつラムダ式内で参照されているので、変更しようとするとコンパイルエラーになる。

##ラムダ式外での書き換えも当然不可
```java:ラムダ式外での書き換えも不可能
package java8sample;

public class Java8Sample {
    public static void main(String[] args) {
        String str = "not final";
        
        MyInterface lambda = () -> System.out.println(str);
        lambda.method();
        
        str = "上書き不可"; // コンパイルエラー
    }
    
    private static interface MyInterface {
        void method();
    }
}
```

#関数インターフェース
抽象メソッドが１つしか存在しないインターフェースのことを __関数インターフェース__ と呼ぶ。
関数インターフェースには、ラムダ式が代入できる。

##`@FunctionalInterface` アノテーションで関数インターフェースを定義する
```java:関数インターフェースの宣言
package java8sample;

@FunctionalInterface
public interface MyInterface {
    void method();
}
```

Java8 で追加された `@FunctionalInterface` アノテーションをインターフェースに付与すると、そのインターフェースは __関数インターフェース__ とみなされる。

`@FunctionalInterface` アノテーションをインターフェースに付与すると、そのインターフェースはメソッドを１つしか宣言できなくなり、複数のメソッドを宣言するとコンパイルエラーになる。
つまり、そのインターフェースにはラムダ式が必ず代入できる、ということをコンパイルレベルで保証できる。

##`java.util.function` パッケージには、よく使いそうな関数インターフェースが定義されている
`java.util.function` パッケージには、関数インターフェースがたくさん定義されている。

- [java.util.function (Java Platform SE 8 b120)](http://download.java.net/jdk8/docs/api/java/util/function/package-summary.html)

基本はここで定義されている関数インターフェースを利用して、どうしても自分のニーズに合わない場合は独自で関数インターフェースを定義する。　　と思う。たぶん。

#関数オブジェクト
##クラスメソッドを関数オブジェクトとして取得する
```java:staticメソッドを関数オブジェクトとして取得する
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        MyInterface func = Java8Sample::staticMethod;
        func.method();
    }
    
    public static void staticMethod() {
        System.out.println("Java8Sample#staticMethod()");
    }
    
    @FunctionalInterface
    private static interface MyInterface {
        void method();
    }
}
```

```text:実行結果
Java8Sample#staticMethod()
```

- `<クラス名>::<クラスメソッド名>` で、そのクラスのメソッドを関数オブジェクトとして取得できる。

##取得しようとしているメソッドがオーバーロードされている場合は、代入先の関数インターフェースに合わせて取得できるメソッドが切り換わる
```java:オーバーロードされているメソッドを関数オブジェクトとして取得する
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        NoneArgument none = Java8Sample::staticMethod;
        none.method();
        
        SingleArgument single = Java8Sample::staticMethod;
        single.method("hoge");
    }
    
    public static void staticMethod() {
        System.out.println("Java8Sample#staticMethod()");
    }
    
    public static void staticMethod(String str) {
        System.out.printf("Java8Sample#staticMethod(%s)%n", str);
    }
    
    @FunctionalInterface
    private static interface NoneArgument {
        void method();
    }
    
    @FunctionalInterface
    private static interface SingleArgument {
        void method(String str);
    }
}
```

```text:実行結果
Java8Sample#staticMethod()
Java8Sample#staticMethod(hoge)
```

- メソッドの参照はどちらも `Java8Sample::staticMethod` となっているが、取得された関数オブジェクトは代入先の関数インターフェースに合わせて切り替わっている。

##インスタンスメソッドを関数オブジェクトとして取得する
```java:インスタンスメソッドの取得
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        Java8Sample sample = new Java8Sample("Hoge");
        MyInterface func = sample::instanceMethod;
        func.method();
    }
    
    private String name;
    
    public Java8Sample(String name) {
        this.name = name;
    }
    
    public void instanceMethod() {
        System.out.println("My name is " + this.name);
    }
    
    @FunctionalInterface
    private static interface MyInterface {
        void method();
    }
}
```

```text:実行結果
My name is Hoge
```

- `<インスタンス>::<インスタンスメソッド名>` で、そのインスタンスのメソッドを取得できる。

##実行時のインスタンスを指定できるインスタンスメソッドを取得する
```java:実行時のインスタンスを指定する
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        MyInterface func = Java8Sample::instanceMethod;
        
        Java8Sample sample = new Java8Sample("Hoge");
        func.method(sample, "hoge");
    }
    
    private String name;
    
    public Java8Sample(String name) {
        this.name = name;
    }
    
    public void instanceMethod(String str) {
        System.out.println("My name is " + this.name + ". str=" + str);
    }
    
    @FunctionalInterface
    private static interface MyInterface {
        void method(Java8Sample instance, String str);
    }
}
```

```text:実行結果
My name is Hoge. str=hoge
```

- `<クラス名>::<インスタンスメソッド名>` で実行時のインスタンスを指定できるインスタンスメソッドが取得できる。
- 関数インターフェース側は、第一引数に実行時のインスタンスが渡せるようにシグニチャを定義する。
- インスタンスメソッドへの引数は、第二引数以降に渡す。

#インターフェースにデフォルト実装が定義できるようになった
```java:インターフェースのデフォルト実装が定義できる
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        new MyClass().method();
    }
    
    private static class MyClass implements MyInterface {
    }
    
    private static interface MyInterface {
        default void method() {
            System.out.println("default method");
        }
    }
}
```

```text:実行結果
default method
```

- `default` をメソッド定義の前につければ、インターフェースでも実装を記述することができる。

##つまり、多重継承が可能になった
```java:
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.hoge();
        myClass.fuga();
    }
    
    private static class MyClass implements Hoge, Fuga {
    }
    
    private static interface Hoge {
        default void hoge() {
            System.out.println("hoge");
        }
    }
    
    private static interface Fuga {
        default void fuga() {
            System.out.println("fuga");
        }
    }
}
```

```text:実行結果
hoge
fuga
```

- インターフェースは複数実装可能なので、事実上多重継承が可能になった

##同じシグネチャのデフォルトメソッドを持つインターフェースを複数実装した場合、実装クラスでオーバーライドしなければならない
```java:
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.method();
    }
    
    private static class MyClass implements Hoge, Fuga { // コンパイルエラー
    }
    
    private static interface Hoge {
        default void method() {
            System.out.println("hoge");
        }
    }
    
    private static interface Fuga {
        default void method() {
            System.out.println("fuga");
        }
    }
}
```

↓オーバーライド

```java:
package java8sample;

public class Java8Sample {
    
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.method();
    }
    
    private static class MyClass implements Hoge, Fuga {
        @Override
        public void method() {
            System.out.println("MyClass");
        }
    }
    
    private static interface Hoge {
        default void method() {
            System.out.println("hoge");
        }
    }
    
    private static interface Fuga {
        default void method() {
            System.out.println("fuga");
        }
    }
}
```

```text:実行結果
MyClass
```

#参考
- [NetBeansカラースキーム6個まとめ｜プログラム｜Nullyのぶろぐ](http://blog.nully.org/2011/10/19/color-scheme-pack-for-netbeans/)
- [NetBeansでConsolasフォントを使う - unoh.github.com by unoh](http://unoh.github.io/2008/11/26/how-to-use-consolas-on-netbeans.html)
- [NetBeans 6.9 開発版を試す:空白やタブを表示する (Masaki Katakai's Weblog)](https://blogs.oracle.com/katakai/entry/netbeans_6_9_dev_shownonprintablechars)
- [NetBeans IDE キーボードショートカット](https://usersguide.netbeans.org/shortcuts_ja.pdf)
- [祝 Java8 Project Lambda リリース！につき、ラムダ式コトハジメ - 倭マンs BLOG](http://waman.hatenablog.com/entry/20130401/1364778128)
- [java.util.function パッケージ - 倭マンs BLOG](http://waman.hatenablog.com/entry/20130313/1363200589)
- [Java8新機能 ラムダ式とデフォルトメソッドの導入理由 - Yuji Blog](http://blog.yujing.jp/entry/2013/06/29/170337)
- [Java8で最もインパクトのある構文拡張、デフォルトメソッド - きしだのはてな](http://d.hatena.ne.jp/nowokay/?date=20130610)