2011年08月01日

ScalaとJavaの相違点の箇条書き

この手の原稿を書くことになった気がするので(気のせいかもしれない)、いろいろまとめ中。

==================================================
変数の宣言

・Java
String str = "文字列";

・Scala(再代入可能の場合)
var str = "文字列"

・Scala(再代入不可の場合)
val str = "文字列"

・Scala(型を明記する場合)
val str: String = "文字列"

==================================================
関数の宣言

・Java
public int sum(int i, int j) {
  return i + j;
}

・Scala(省略なし)
def sum(i: Int, j: Int): Int = {
  return i + j
}

・Scala(Rubyと同じでreturnは不要)
def sum(i: Int, j: Int): Int = {
  i + j
}

・Scala(戻り値も型推論可能)
def sum(i: Int, j: Int) = {
  i + j
}

・Scala(1行の場合は括弧不要)
def sum(i: Int, j: Int) = i + j

・Scala(引数を省略した場合)
def sum = (_: Int) + (_: Int)

==================================================
static

・Java
class Sample {
  public static String STR = "文字列";
}

・Scala
object Sample {
  def String STR = "文字列"
}

Scalaではstaticキーワードは存在しない。その代わり、objectが用意されている。objectはシングルトンのインスタンス。objectの中で宣言した変数や関数は、Javaのstaticで宣言したものとだいたい同じように利用できる。

==================================================
三項演算子

・Java
public int max(int i, int j) {
  return i > j ? i : j;
}

・Scala
def max(i: Int, j: Int): Int = {
  return if (i > j) i else j
}

Scalaではif〜elseが値を返す。ので、if〜elseで三項演算子と同様の動きができる。

==================================================
for文(10回繰り返す)

・Java
for (int i = 0; i < 10; i++) {
  System.out.println(i);
}

・Scala
for (i <- 0 to 9) {
  println(i)
}

==================================================
for文(九九の結果表示)

・Java
for (int i = 1; i < 10; i++)
  for (int j = 1; j < 10; j++)
    System.out.println(i * j);

・Scala
for (i <- 1 to 9)
  for (j <- 1 to 9)
    println(i * j)

・Scala(入れ子を1つのforにまとめることも可能)
for (i <- 1 to 9; j <- 1 to 9)
  println(i * j)

==================================================
数値型

・Java
int, short, long, double, float, char

・Scala
Int, Short, Long, Double, Float, Char

基本、大文字。Scalaの数値はプリミティブではなくオブジェクト。なので「10.toString」や「10.max(12)」のような記述ができる。

==================================================
インクリメント

・Java
int i = 0;
i++;
i += 1;

・Scala
var i = 0;
i += 1;

「i++」という表記はできない。もちろん「++i」も「i--」も「--i」もできない。数値がプリミティブでない言語はできない場合が多い。

==================================================
break

・Java
int i = 0;
while(true) {
  System.out.println(i);
  if(i > 100) break;
  i++;
}

・Scala
import scala.util.control.Breaks.{ break, breakable }
breakable {
  var i = 0
  while (true) {
    println(i)
    if (i > 100) break
    i += 1
  }
}

・Scalaではbreakはあまり使うものではない(再帰を使ったループが一般的)
def loop(i: Int): Unit = {
  println(i)
  if (i < 100) loop(i + 1)
}
loop(0)

==================================================
continue

・Java
for (int i = 0; i < 10; i++) {
  if (i % 2 == 0)
    continue;
  System.out.println(i);
}

・Scala
continueなんてない。但し、上記と同様の処理であれば、下記のような記述が可能。

for (i <- 0 to 9 if i % 2 != 0) {
  println(i)
}

==================================================
switch

・Java
int i = 2;
switch (i) {
case 1:
  System.out.println("いち");
  break;
case 2:
  System.out.println("に");
  break;
default:
  System.out.println("たくさん");
  break;
}

・Scala
val i = 2
i match {
  case 1 => {
    println("いち")
  }
  case 2 => {
    println("に")
  }
  case _ => {
    println("たくさん")
  }
}

==================================================
コンストラクタ

・Java
public class Sample {
  public Sample() {
    this(-1);
  }

  public Sample(int i) {
    // コンストラクタの処理
  }
}

・Scala
class SampleS(i: Int) {
  // コンストラクタの処理

  def this() {
    this(-1)
  }
}

Scalaのコンストラクタはクラスの宣言のところに引数を書く。オーバーロードは「def this(引数)」で宣言する。

オーバーロードしたコンストラクタは、必ず他のコンストラクタを呼び出さないといけない。この辺はJavaより少し制限が厳しい。

==================================================
インターフェース

・Java
interface Interface1 { public void foo(); }
interface Interface2 { public void bar(); }

class Sample implements Interface1, Interface2 {
  public void foo() { /* 実装 */ }
  public void bar() { /* 実装 */ }
}

・Scala
trait Trait1 { def foo() }
trait Trait2 { def bar() { /* 実装 */ } }

class Sample extends Trait1 with Trait2 {
  def foo() { /* 実装 */ }
}

Scalaではtraitを利用する。traitはインターフェースと違って、中に実装を書いておくこともできる。Traitが3つある場合は、「extends Trait1 with Trait2 with Trait3」のようにwithが連なる。

==================================================
継承

・Java
class Child {
  public Child(int i, int j) {
    /** 処理 */
  }
}

class Parent extends Child {
  public Parent(int i, int j) {
    super(i, j);
  }
}

・Scala
class Parent(i: Int, j: Int) {
  /** 処理 */
}

class Child(i: Int, j: Int) extends Parent(i: Int, j: Int)

継承時は「Parent(i: Int, j: Int)」のように継承するコンストラクタの引数も記述する。

==================================================
void

・Java
// 戻り値なし
public void foo() { }

・Scala
// 戻り値なし
def foo(): Unit { }

正確には戻り値なしではなくUnit型(空っぽの値)を返す。

==================================================
Object

・Java
すべてのクラスはObjectを継承している。

・Scala
すべてのクラスはAnyを継承している。また、IntやDoubleなどのJavaのプリミティブ型に対応するクラスはAnyValを、それ以外のクラスはAnyRefを継承している。

==================================================
throws

・Java
public void foo throws Exception {
  // 処理
}

・Scala
def foo {
  // 処理
}

Scalaではthrowsは記述しない。

==================================================
==による比較

・Java
String str1 = "文字列";
String str2 = new String("文字列");
System.out.println(str1 == str2);
  //=> false

・Scala
val str1 = "文字列"
val str2 = new String("文字列")
println(str1 == str2)
  //=> true

Scalaの==はequalsを呼び出す。ので、値が等しければ==の結果はtrueになる。Javaと同じようにオブジェクトの比較を行う場合は「str1 eq str2」。

==================================================
import

・Java
import java.util.List;
import java.util.ArrayList;
import java.io.*

・Scala(同じような書き方)
import java.util.List
import java.util.ArrayList
import java.io._

・Scala(同じパッケージをまとめる)
import java.util.{ List, ArrayList }

・Scala(途中までimport)
import java.util
import util.{ List, ArrayList }

パッケージ内をすべてimportする場合はJavaではアスタリスクだが、Scalaではアンダーバー。その他、いろいろ小器用な書き方が可能になっている。

==================================================
.class

・Java
Class cls = String.class;

・Scala
val cls = classOf[String]

==================================================
キャスト

・Java
ArrayList<String> arrayList = new ArrayList<String>();
List<String> list = (List<String>) arrayList;

・Scala
val arrayList = new ArrayList[String]()
val list = arrayList.asInstanceOf[List[String]]

==================================================
型変換

・Java(数値 → 文字列)
String.valueOf(100);

・Scala(数値 → 文字列)
100.toString

・Java(文字列 → 数値)
Integer.parseInt("100");

・Scala(文字列 → 数値)
"100".toInt

==================================================
catch

・Java
try {
  // 処理
} catch (Exception e) {
  e.printStackTrace();
} finally {
  // 処理
}

・Scala
try {
  // 処理
} catch {
  case e: Exception => {
    e.printStackTrace;
  }
} finally {
  // 処理
}