第15章：Scalaの制御構造

最近、型り（語り）まくっていたけど、今回は制御構造だよ。

Scalaではどんな制御構造があるのでしょうか？

# Scalaの制御構造
__処理をどのように実行するかを決めること__

制御構造をザックし言ってみました。
これを実現するために、多くのプログラミング言語ではifやfor等が用意されています。

Scalaの制御構造以下となっています。

- if
- for
- while
- try
- match
- 関数呼び出し

JVMを使っているからJavaと違いがないと思いきや
やっぱり別言語なので違いがありますね。。

今回は制御構造とあわせて、変数のスコープ等についても紹介していきます。

# if
選択構造の代表です。 __if式__ と呼びます。
以下の記述は違和感なく読むことができると思います。

```scala:IfTest1.scala
import java.io.File

object IfTest1 {

  def main(args: Array[String]): Unit = {
    var filename = "config.txt"

    if (!args.isEmpty)
      filename = args(0)

    println("Filename:" + filename)
  }

}
```

ifの条件式 `!args.isEmpty` が true に成った場合、
つまりパラメータ指定で実行した時に `filename` の値を入れ替えます。
`if` の普通な使い方だと思います。

でもよーく見ると。これイケてないですよね？
変数がイミュータブルになっていないし、再代入しているし。

このような場合例えば Java だと、`filename` の確定処理をメソッドとして
切りだすと思うのですが、Scala での `if` は式のため、値を返すことができるのです。

では `if` が値を返すようにリファクタリングしたソースを見てみよう。

```scala:IfTest1Refactor.scala
import java.io.File

object IfTest1Refactor {

  def main(args: Array[String]): Unit = {
    val filename = if (args.isEmpty) "config.txt" else args(0)

    println("Filename:" + filename)
  }

}
```

変数 `filename` をイミュータブルに変更することができ
しかも値の確定処理を変数の宣言と共に1行にすることができました。

`if` を使うと、宣言と値の定義が1箇所に纏まって見やすくなりましたね。

# for
繰返構造の代表です。所謂ループってやつです。
__for式__ と呼びます。

まずは基本的な使い方から。
コンソールで試してみます。

```scala
scala> val list = List("Brad Jones", "Steven Gerrard", "Daniel Agger", "Daniel Sturridge")
list: List[java.lang.String] = List(Brad Jones, Steven Gerrard, Daniel Agger, Daniel Sturridge)

scala> for (name <- list) { println(name) }
Brad Jones
Steven Gerrard
Daniel Agger
Daniel Sturridge
```

Java の拡張 for 文と似ていますね。

ここから for 式のパワーを見てみましょう。

## フィルタリング
Java と違って、Scala ではフィルタリングが簡単に実現できます。

```scala
scala> for (name <- list if name.startsWith("Daniel")) { println(name) }
Daniel Agger
Daniel Sturridge
```

`Daniel` で始まる文字列だけでフィルタリングしてみました。
Java だと Commons Collections を用意したりで、面倒くさくなります。

試しにCommons Collections を使って上のソースと
同じモノをJavaで実現してみました。

```java:JavaFiltering.java
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
import org.apache.commons.lang3.StringUtils;

public class JavaFiltering {

	public static void main(String[] args) {
		final List<String> list = Arrays.asList("Brad Jones", "Steven Gerrard",
				"Daniel Agger", "Daniel Sturridge");

		final Iterator<String> iterator = new FilterIterator(list.iterator(),
				new Predicate() {

					@Override
					public boolean evaluate(Object object) {
						final String name = (String) object;
						return StringUtils.startsWith(name, "Daniel");
					}
				});

		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}

}
```

Scalaだとこの1行ですが

```scala
for (name <- list if name.startsWith("Daniel")) { println(name) }
```

Javaだと、

```java
final Iterator<String> iterator = new FilterIterator(list.iterator(),
		new Predicate() {

			@Override
			public boolean evaluate(Object object) {
				final String name = (String) object;
				return StringUtils.startsWith(name, "Daniel");
			}
		});

while (iterator.hasNext()) {
	System.out.println(iterator.next());
}
```

のように、 `Predicate` でフィルタリング条件を作って
フィルタリングする `Iterator` 作ったりでかなり長くなってしまいました。
完全に冗長に書いてはいますけどね。

Scala は簡単過ぎます！

## 新しいコレクションの生成
フィルタリングでは繰返の中で値を使いましたが
フィルタリング結果を新しいコレクションにすることも可能です。

```scala
scala> val daniels = for { name <- list if name.startsWith("Daniel") } yield name
daniels: List[java.lang.String] = List(Daniel Agger, Daniel Sturridge)

scala> for (name <- daniels) { println(name) }
Daniel Agger
Daniel Sturridge
```

ここで `yield` が登場しています。
`for` は戻り値がないですが、`yield` を使うと演算結果をコレクションにして
返すことができます。

# while
これも繰返構造の代表ですね。
Scala での使い道がわかっていないので
サラッと紹介します。

## whileループ
```scala
scala> var count = 0;
count: Int = 0

scala> while (count < 5) {
     |   count += 1
     |   println(count)
     | }
1
2
3
4
5
```

`while` の条件式が `true` である間、コードブロックを実行します。

## do-while ループ
まずはコードからです。

```scala
scala> var count = 0;
count: Int = 0

scala> do {
     |   count += 1
     |   println(count)
     | } while (count < 5)
1
2
3
4
5
```

`while` と `do-while` の違いは、
`while` は条件式の評価を先にします。
`do-while` はコードブロックを先に実行し、条件式を評価します。

# 変数のスコープ
変数の生存範囲ですね。
変数は基本的には中括弧 `{}` 内でのみ生存できます。

ある生存範囲では、同じ変数を宣言できません。
なので次の場合は、エラーとなります。

```scala
scala> {
     |   val variable = "a"
     |   val variable = "b"
     | }
<console>:10: error: variable is already defined as value variable
                    val variable = "b"
                        ^
```

そして、外側の中括弧で宣言した変数は、その内部の中括弧でも
使用可能です。以下は、外側の中括弧で宣言した変数 `count` を、
`while` の中括弧内で使用しています。

```scala
scala> {
     |   val variable = "a"
     |
     |   {
     |     println(variable)
     |   }
     | }
a
```

ここまではJava と変わらないんだけど、最後に「Scala 固有の規則」です。

Scala では、そして、外側の中括弧で宣言した変数は、
その内部の中括弧でも __宣言__ 可能です。

```scala
scala> {
     |   val variable = "a"
     |
     |   {
     |     val variable = "b"
     |     println(variable)
     |   }
     | }
b
```

この時、 __内部の変数は外側の変数をシャドウイングしている__ と表現します。

実はコンソール上の動きは、シャドウイングしてたりします。

ただこのシャドウイング、ソースを書く上では全く使い道がわからないです。
スコープの小さい `if` 式とかで、変数名を考えるのが面倒臭い時等に使うくらいかな。

読み辛くなる可能性が高いので、あまり使わない方が良いですね。

# 例外 (Exception)
例外とは、 __処理の異常時に戻り値とは別のやり方で呼出元に通知する仕組み__ です。
呼出元は例外発生の通知を受け取った時に、以下なことをするのが多いです。

- 上位に更に通知を出す(上位に伝播させる)
- 別の処理(所謂、準正常系や異常系の処理)を実施する


## 例外を作る (throw)
例外を作るのは簡単です。
以下のようにするだけです。

```scala
throw new FileNotFoundException
```

これで `FileNotFoundException` という例外を生成して、上位に投げています。
__スローする__と言ったりします。

実際に試してみたのが以下となります。

```scala
scala> throw new java.io.FileNotFoundException
java.io.FileNotFoundException
        at .<init>(<console>:8)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
        at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
        at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
        at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
        at java.lang.Thread.run(Thread.java:722)
```

これで自分で例外の生成ができるようになりますね！

## 例外を捕える (try/catch)
次に、下位でスローされた例外の通知を検知できるようにします。
__例外をキャッチする__と言ったりします。

__try/catch 節__というのを使います。
ソースをみてみましょう。

コンソールで動かした結果も載せたいので
パッケージ名載せて見辛くなっているはゴメンナサイ。

```scala
scala> try {
     |   val input = new java.io.FileInputStream("input.txt")
     | } catch {
     |   case ex: java.io.FileNotFoundException => println("File not found")
     |   case ex: java.io.IOException => println("IOError")
     | }
File not found
```

### 例外クラス
まず2つの例外クラスについて説明します

- java.io.FileNotFoundException
  - 実ファイルが存在しない場合にスローされる

- java.io.IOException
  - 書き込みが失敗する等のIO系のエラーが発生した場合にスローされる

java.io.FileInputStream のインスタンスを作った時に
この2つの例外がスローされると予測しています。

### catch
例外をキャッチします。
そして`case`でパターンマッチを行っています。

このソースを実行した時に、「input.txt」というファイルが存在していなかったので
「File not found」と出力されました。

### try
どこで発生した例外を対象にするかを決めます。
`try` で始まる中括弧の中で発生した例外がのみが、
キャッチ対象となるわけです。

## finally
例外がスローされると後続の処理が実施されません。
正常系でも例外が発生しても、最後に確実に実行させたい処理がある場合に使用します。

```scala
scala> {
     |   val input = new java.io.FileInputStream("input.txt")
     |
     |   try {
     |     throw new java.io.IOException // 明示的に例外をスロー
     |
     |     input.close() // 例外がスローされているので、ここには到達しない
     |   } catch {
     |     case ex: java.io.FileNotFoundException => println("File not found")
     |     case ex: java.io.IOException => println("IOError")
     |   } finally {
     |     println("Finally")
     |     input.close()  // 例外が発生しても、しなくてもここに入ってくる
     |   }
     | }
IOError
Finally
```

よくあるのがファイルのクローズですね。

## Scalaの例外
最後に、Scala ではJava と違ってチェック例外のキャッチが必須ではないです。
チェック例外って何って？

Javaの例外には2種類あります。

- チェック例外
- 非チェック例外

### チェック例外
Exception クラスをを継承しているクラスをスローして発生させる例外。
`throws` を強制される。

上位では以下のいずれかが必要となる。

- キャッチする
- `throws` 宣言をして、更に上位にスローする

### 非チェック例外
RuntimeException クラスを継承しているクラスをスローして発生させる例外
`throws` を強制されない。

上位でのキャッチや `throws` 宣言は必須ではない。

つまりScala では、Java における __非チェック例外__ のように例外を扱えます。

# まとめ
制御構造にしてみたけどどうだった？

今回、 __match__ については触れなかったけど、別の機会で語ります。

今回も
__体で感じてくれたかな？__