はじめに
主にJavaエンジニア目線から見た、こんなことをしたいのだけど(Javaは or Swiftは)これできないの? というときに利用するTipsになります。
Java 8が発表され、Android Studio 3.0ではKotlinが正式採用されましたが、JavaばかりやっていたエンジニアがいざXcodeでiOSアプリを開発する場合や、iOSアプリをSwiftで開発していたエンジニアがJavaでAndroidを開発しようとする場合に言語の記法レベルで確認したい場合のご助力になれば幸いです。
このページでは、主に「ソース管理」「スコープ」「変数」のJava/Swiftの記法について取り上げます。
本記事はJavaの場合は1.7、Swiftの場合はSwift3を基準に記載しておりますが、もし記法ミス等があったら申し訳ありません。
- JavaとSwift比較(1) ソース管理 / スコープ / 変数 編
- JavaとSwift比較(2) 基本的な型 / 演算式 / 制御構文 / 関数定義 編
- JavaとSwift比較(3) クラス実装 / クラスの継承 / クラス設計 編
ソース管理
Java
パッケージで管理され、パッケージは(一般には)ディレクトリの階層単位で決定されます。
同じプロジェクト内のクラスでも、aaa.bbb.cccのパッケージ内のTest.classとaaa.bbb.xxxのパッケージ内のTest.classでは別のクラスとして取り扱われ、また作成することができます。
ただし、同じプロジェクト内であれ、異なるパッケージのクラスを利用する場合、『import インポート対象』と、ソースファイル先頭に宣言するか、完全修飾子でアクセスする必要があります。
ただし、java.langパッケージは使用頻度の高いクラス群が含まれており、これらに含まれたクラス(String、Integer等)は明示的にインポートせずに使用することができます。
import java.util.List;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList();
java.util.Map<String, String> list = new java.util.HashMap<>();
}
}
ソースファイル
ソースファイルは「*.java」拡張子である必要があります。
また、Javaソースファイルには、publicなクラスは一つしか含めることができず、Javaソースファイル名とpublicなクラス名は一致している必要があります。
Swift
Swiftはモジュール(プロジェクト)単位でパッケージが決定され、モジュール名が名前空間として決定されます。
したがって、同じモジュール内であれば、ディレクトリの階層、ソース問わずにクラス名のみでアクセスできますが、クラス名の競合に十分注意する必要があります。
このとき、別のモジュール(たとえばライブラリプロジェクト)のクラスを使用する場合、ソースファイル先頭に「import インポート対象パッケージ」と宣言するか、「対象パッケージ.クラス名」というように完全修飾子でアクセスする必要があります。
import Foundation
class Main {
var arr:Array = Array<String>()
var date:Foundation.Date = Foundation.Date()
}
ソースファイル
ソースファイルは「*.swift」拡張子である必要があります。
また、Swiftソースファイルは、Javaとは異なり、任意のファイル名をつけることができます。また、一つのファイル名にスコープ問わず複数のクラスを定義することができます。
スコープ
Java
Javaでは基本的にパッケージ、クラス単位でアクセス制御が決定します。
アクセス修飾子 | 説明 |
---|---|
public | すべてのクラス、パッケージからアクセス可能 |
protected | 同一パッケージ内とサブクラスからアクセス可能 |
(修飾子なし) | 同一パッケージ内からアクセス可能 |
private | 同一クラス内からのみアクセス可能 |
Swift
Swiftでは基本的にモジュール、ファイル単位でアクセス制御が決定されます。
アクセス修飾子 | 説明 |
---|---|
open | すべてのクラス、異なるモジュールからアクセス可能(Swift3以降) |
public | すべてのクラス、異なるモジュールからアクセス可能、Overide不可 |
internal | 同一モジュール内からアクセス可能 |
(修飾子なし) | 「internal」と同じアクセスコントロール |
fileprivate | 同一ファイル内からアクセス可能(Swift3以降) |
private | 同一ファイル内からのみアクセス可能 |
変数
まず、どちらも静的型付け言語です。
コンパイル時より以前に型は決定されており、Javaなどは変数の宣言時で明示的に指定することから瞭然ではありますが、Swiftのように変数宣言時に「var hoge1 = hoge2」といった記法の場合でも、型推論により変数の型は宣言された時点で決定されています。
Java
変数宣言方法
「型名 変数名 = 初期値;」と指定します。
String hoge = "";
初期値は宣言時には必須ではなく、「型名 変数名;」と宣言することも可能ですが、実際に変数にアクセスする際に値が設定されていない場合はコンパイルエラーが発生します。
また、値が不定である場合はnullを指定することが可能ですが、nullである変数にアクセスしようとした場合はNullpointerException例外が発生します。
定数宣言方法
「final 型名 変数名 = 初期値;」と指定します。Swiftの定数宣言と同様に、初期値を設定後以降値の再設定できません。
final String hoge = "";
なお、Javaは完全なオブジェクト指向の言語であるため、変数や定数は必ずクラス、またはインスタンスに紐付き、クラス外に変数や定数を定義できません。
このとき、クラスに紐付く定数を定義する場合はstatic(静的)なfinal(定数)と宣言し、これをクラス定数と呼び、「static final 型名 変数名 = 初期値;」と指定します。
クラス定数は大文字英数字で宣言するJava命名規則上で定められています。
Swift
変数宣言方法
「var 変数名:型名 = 初期値」と指定します。
また、SwiftにはOptional Typeという言語仕様が存在し、非Optional型である変数にはnilを設定することができません。
var hoge:String = ""
Optional Typeとは
Java8のOptional型、KotlinのOptionalに相当します。
Optional Typeとは、変数の型がもつ通常の値に加えて、nil状態を保持できる変数です。Optional Typeの初期値はnilが設定されます。SwiftではJavaとは違い、Optional Typeではない変数は必ずnil(null)ではないことが記法レベルで保証されます。
Optional Typeは明示的な指定と、変数利用時に自動的にアンラップする指定があります。
明示的なOptional Type
「var 変数名:型名? = 初期値」というように、型名の後ろに「?」を指定します。
var hoge:String? = ""
明示的なOptional Typeを指定した場合、変数は元の型と同じように利用することはできず、使用時にはアンラップする必要があります。
明示的なOptional Typeをアンラップせずに操作しようとすると、コンパイルエラーが発生します。
var hoge:String? = "ABC" // 明示的なOptional Typeで変数を宣言
print(hoge.lowercased()) // コンパイルエラー
Optional Typeのアンラップ
Optional Typeのアンラップとは、Optional Typeの変数を元の型と同じように利用できるようにすることです。
アンラップにもいくつか方法があり、プログラム上nilの可能性がない場合に使用するべきアンラップや、プログラム上nilの可能性がある場合に使用するべきアンラップがあります。
nilの可能性がない場合
「変数名!.操作」というように、型名の後ろに「!」を指定後、プロパティやメソッドなどの操作を記述します。
var hoge:String? = "ABC" // 明示的なOptional Typeで変数を宣言
print(hoge!.lowercased()) // ”abc”と出力される
ただし、アンラップしようとした変数がnilの場合、実行時にランタイムエラーが発生します。
hoge = nil // Optional Typeにはnilを設定できる
print(hoge!.lowercased()) // ランタイムエラーが発生する
このため、次のようなプログラムを記述する場合に効果を発揮します。
var hoge:String?
if Date().timeIntervalSince1970 > 0 {
hoge = "abc"
} else {
hoge = "cde"
}
print(hoge!.lowercased())
nilの可能性がある場合
「変数名?.操作」というように、型名の後ろに「?」を指定後、プロパティやメソッドなどの操作を記述します。
「変数名!.操作」で強制的にアンラップした場合と違い、nilが返却されます。
var hoge:String? = nil // Optional Typeにはnilを設定できる
print(hoge?.lowercased()) // ランタイムエラーは発生せず、nilが出力される
暗黙的なOptional Type
「var 変数名:型名! = 初期値」というように、型名の後ろに「!」を指定します。
var hoge:String! = ""
暗黙的なOptional Typeを指定した場合、変数使用時にはコード上で明示的にアンラップする必要はなく、利用時に自動的にアンラップされます。
var hoge:String! = "ABC" // 暗黙的なOptional Typeで変数を宣言
print(hoge.lowercased()) // 明示的にアンラップしなくても利用可能。”abc”と出力される
このため、変数を利用する場合には基本的にnilであることを考慮せずに元の型を利用することができますが、nilが設定されたOptional Typeの変数を操作しようとすると、ランタイムエラーが発生します。
var hoge:String! = "ABC" // 暗黙的なOptional Typeで変数を宣言
hoge = nil // Optional Typeにはnilを設定できる
print(hoge.lowercased()) // ランタイムエラーが発生する
暗黙的なOptional Type場合は十分にその変数を利用する場合にじゅうぶんにnilでないことを保証されるように実装する必要があります。
定数宣言方法
「let 変数名:型名 = 初期値;」と指定します。Javaの定数宣言と同様に、初期値を設定後以降値の再設定できません。
let hoge:String = ""
なお、SwiftはJavaとは異なり、オブジェクト指向の言語ではないため(Swiftはプロトコル指向の言語になります)、必ずしもクラス、またはインスタンスに紐付く必要はなく、ファイル内に直接定数を定義することができます。
ファイル内に直接定義された定数の場合、実質的に静的に不変であることが保証されます。