0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutter 学習メモ(Dartの基本仕様)(Java経験者向け)

Last updated at Posted at 2025-10-26

お願い
本記事の内容に誤りや改善点がございましたら、コメント等でご指摘いただけますと幸いです。
なお、本記事は個人の学習記録として作成したものです。業務でご利用の際は、公式ドキュメントもあわせてご確認ください。

1. はじめに

会社でFlutter(Dart)を使うことになり、まったく触ったことがなかったため、普段使っているJavaとの比較を交えながら気になったDartの特徴を抜粋して整理してみました。

補足
本記事はサンプルコードを載せていますが、dartpadというサイトを使えばweb上で実行できます!
https://dartpad.dev

2. Dartとは

DartはGoogleが開発した静的型付けのプログラミング言語で、クロスプラットフォーム開発で活用されています

特徴

  • 強い型付けとnull安全機能を搭載
  • AOT(Ahead-of-Time)とJIT(Just-In-Time)の両方のコンパイルに対応
  • Flutterとの親和性が高く、クロスプラットフォーム開発に対応
  • 非同期処理を扱いやすいasync/await構文をサポート

補足

3. プロジェクト作成と実行

Dartは .dart という拡張子のファイルを使用します。

// sample/hello.dart

void main() {
  print('Hello');
}

下記のコマンドで実行することができます。

# ファイルのパスを指定して実行
dart run sample/hello.dart

4. ライブラリとpart構文

  • Dartでは 1つのソースファイル = 1ライブラリ として扱われます。
    part を使えば複数ファイルをまとめて1つのライブラリとして定義できます。)

5. 型と演算子

サンプルコード
5. 型と演算子

5-1. Java vs Dart 型対応表

Javaの分類 Javaの例 Dartの例 Dartの挙動 備考
基本型 int, double, boolean int, double, bool 値コピーのように動く(実際はすべてObject) Dartはプリミティブもクラス扱い(int などもObject)
文字列 String String 参照型だがイミュータブル Javaとほぼ同じ
コレクション List, Set, Map List, Set, Map 参照渡し Dartはリテラル構文([], {})で生成可能
ラッパー型 Integer, Double 不要 DartではプリミティブもObject オートボクシング不要
レコード/タプル record Record 値をまとめる軽量構造体(イミュータブル) Dart独自。Javaのrecordに近い。
null許容 基本型は不可 int?, String? 型ごとに指定 Dartは基本的にはNull安全

5-2. ライブラリの使い方

  • 文字列結合
String a = "あいう";
print("結果は $a です");   // 文字列補間(推奨)
print("結果は " + a + " です"); // 文字列連結(冗長。パフォーマンス低下の恐れあり)
  • ListとSet
特徴 List Set
順序 あり(インデックスでアクセス可) あり(デフォルトがLinkedHashSetの実装になっているため)
重複 許可 不許可
主な操作 add, removeAt, insert add, remove, contains
使用例 順序付きデータ 集合演算、重複排除
  • record(レコード)

Javaのrecordに近い。複数値の返却が便利。

void main() {

  // recordの宣言
  var user = (id: 1, name: "Taro");

  // 名前付きフィールドの分解
  var (id: userId, name: userName) = user;

  print("id = $userId, name = $userName");
  // id = 1, name = Taro
}
void main() {
  // 関数の戻り値での分解
  var (name, age) = getUser();

  print("name = $name, age = $age");
  // name = Taro, age = 25
}

(String, int) getUser() {
  // record型で返却
  return ("Taro", 25);
}

5-3. 比較演算子

  • ==, !=, <, >, <=, >= が利用可能
  • == デフォルトでは参照比較
    (Stringや数値型など、一部のクラスでは値の比較になるようオーバーライドされている)

6. 変数と定数(スコープ)

サンプルコード
6-1. Java vs Dart 変数のスコープ対応表 ~ 6-3. コンストラクタでの初期化
6-4. null安全関連の演算子
6-5. 引数の指定
6-6. ゲッターとセッター

6-1. Java vs Dart 変数のスコープ対応表

種類 Dartでの定義 Javaとの違い
トップレベル変数 var / 型指定 / 必要に応じて final / const Javaには存在しない(必ずクラスが必要)
インスタンス変数 var / 型指定 / 必要に応じて final Dartは late で遅延初期化可
クラス変数 static / static final / static const Javaの static と同じ。ただし Dartは static const が使える
ローカル変数 関数・メソッド内に定義(var / 型指定 / final など) Javaと同じ

補足:
Dartのprivate(ライブラリ内限定)は _ プレフィックス で表現。

6-2. finalconst の違い

  • final

    • 特徴:
      値はランタイム時に決まる。
      利用時までに決まっていればいいので、必ずしもインスタンス生成時に初期化する必要はない。

      class Person {
        late final String message;
      
        void assignMessage(bool flag) {
          if (flag) {
            message = "こんにちは";
          } else {
            message = "Hello";
          }
        }
      }
      
      void main() {
        var p = Person();
        p.assignMessage(true);  // 利用前に初期化
        print(p.message);  // OK(利用時に初期化されている)
      }
      

      再代入は不可だが、参照先オブジェクトは変更できる。

    • 使いどころ:
      APIレスポンスやユーザー入力など「実行時に決まる値」を固定する。

  • const

    • 特徴:
      値はコンパイル時に決まる。
      必ず宣言とともに固定値で初期化する。

      const now = DateTime.now(); // エラー(実行時にしか分からない)
      const String name = "Alice"; // OK
      

      基本的にはクラス変数に使用できない。
      (クラスのフィールドは「インスタンスを作って初めて値が入る」ので、コンパイル時には値が決まらないため)
      ( 静的変数 (static) であれば使用可能)

      class Person {
        const String name = "Alice"; // エラー
        final String name = "Alice"; // OK
      }
      

      インスタンスも「完全に不変(immutable)」になる。

      void main() {
        const p1 = Point(1, 2); // このインスタンスは完全に不変
        final p2 = Point(1, 2); // final だけでは中のフィールドは不変でも const ではない
      }
      

    • 使いどころ:
      文字列リテラルやWidgetツリーの中の定数化できる部分。const Text('Hello') のように使うとWidgetの再構築が最適化される。

6-3. コンストラクタでの初期化

class Person {
  final String name;
  final int age;

  // パターン1
  Person(this.name, this.age);

  // パターン2
  // Person(String name, int age) : name = name, age = age;

}

6-4. null安全関連の演算子

演算子 意味
? null許容型宣言
! nullではないことを保証
?. nullならアクセスせずnull返却
?? nullならデフォルト値を使用
??= nullなら代入

補足
late修飾子を使用するとコンパイラのnullチェックを回避することができる(遅延初期化)。

6-5. 引数の指定

  • 省略可能位置引数

    • [] で囲むと省略可能
    • デフォルト値を設定できる
    void greet(String name, [int age = 0]) {
      print("Hello $name, age $age");
    }
    
    greet("Alice");      // age はデフォルト 0
    greet("Bob", 25);    // age を指定可能
    
  • 名前付き引数

    • {} で囲む
    • 呼び出すときに 引数名を指定する
    • デフォルト値を設定できる
    • 必須にする場合は required を使う
    • 引数の順序を変えられる
    void greet({required String name, int age = 0}) {
      print("Hello $name, age $age");
    }
    
    greet(name: "Alice");      // OK
    greet(name: "Bob", age: 25); // OK
    greet(age: 25, name: "Bob"); // OK
    // greet(age: 30);           // エラー(name が必須)
    

6-6. ゲッターとセッター

Dartではゲッターとセッターの定義が3パターンに分かれます。

変数の種類 ゲッター セッター
public 変数 自動であり
(クラス外からアクセス可能)
自動であり
(クラス外から設定可能)
public 変数
( final / const )
なし
(変更不可)
private 変数 自動であり
(クラス内でのみアクセス可能)
自動であり
(クラス内でのみ設定可能)
class Person {
  // 暗黙のゲッター・セッターがあるパブリック変数
  String name = "Alice";

  // プライベート変数(カスタムゲッター・セッターでアクセス)
  int _age = 20;

  // カスタムゲッター
  int get age {
    print("age を取得しました");
    return _age;
  }

  // カスタムセッター
  set age(int value) {
    if (value < 0) {
      print("年齢は正の値で設定してください");
    } else {
      print("age を $value に設定しました");
      _age = value;
    }
  }
}

void main() {
  var person = Person();

  // 暗黙のゲッター・セッター
  print("name: ${person.name}"); // Alice
  person.name = "Bob";            // セッター呼ばれる(暗黙)
  print("name: ${person.name}"); // Bob

  // カスタムゲッター・セッター
  print("age: ${person.age}");    // age を取得しました → 20
  person.age = 25;                // age を 25 に設定しました
  print("age: ${person.age}");    // age を取得しました → 25
  person.age = -5;                // 年齢は正の値で設定してください
}

7. 修飾子

7-1. Dart と Java のアクセス修飾子比較表

Dart Java 説明
public(明示的には書かない) public Dart ではデフォルトで すべてのクラスや変数がpublic
_ (アンダースコア) private Dartはライブラリ内であればアクセス可能
なし protected / package-private(デフォルト) Dart には protected や package-private は存在しない。ライブラリ単位でのアクセス制御が基本。

7-2. Dart と Java の継承制御比較表

Dart Java 説明
extends extends 多重継承できない
implements implements 多重継承できる
with なし withmixin という機能で使用する。
base なし このクラスを implements することを禁止し、extends のみ許可する。プライベートメソッドを含めて、全体の整合性を保つために使用する。
interface interface このクラスを extends することを禁止し、implements のみ許可する(実装を隠蔽し、型定義としてのみ利用させたい場合に使う)。Java の interface とは用途が異なる。

7-3. Dart と Java のその他比較表

サンプルコード
sealedクラス

Dart Java 説明
final final Dartは基本null安全だが late を使用して遅延初期化できる
sealed sealed 自身が宣言されたライブラリ以外で、サブクラスの作成を制限できる。
abstract abstract 抽象メソッドを含むか、直接インスタンス化させたくない場合に使用。両言語とも同様の意味。
mixin / with なし Dart 独自の仕組み。多重継承をする際に使用する。
enum enum Java とほぼ同じ。
external なし Dart 独自の仕組み。Dart 以外(ネイティブ・他ライブラリ)で定義されている実装を使うときに宣言する。
static static Java とほぼ同じ。

8. 例外処理

サンプルコード
8. 例外処理

8-1. 例外処理の書き方

try {
  int result = 10 ~/ 0; // 整数割り算
} on IntegerDivisionByZeroException catch (e) { // 例外の型を指定
  print("0除算: $e");
} catch (e, st) { // 第一引数:例外オブジェクト、第二引数:スタックトレース(省略可)
  print("その他: $e");
  print(st);
}

補足
dartには割り算が3種類ある

演算子 説明 戻り値
/ 割り算 double
~/ 整数割り算 int(小数切り捨て)
% 剰余(余り) int

今回の場合、 / を使うと double型のInfinity という特別な値を返するだけで例外にならない。

9. その他の記法、実装

サンプルコード
9-3. 名前付きコンストラクタ
9-4. factoryコンストラクタ
9-5. 拡張メソッド

9-1. カスケード記法

オブジェクトに対して連続的に操作できる(Javaにはない記法)。

var buffer = StringBuffer()
  ..write("Hello")
  ..write(" World")
  ..write("!");
print(buffer.toString()); // Hello World!

9-2. パターンマッチング(if-case / switch)

// if-case + when の例
void main() {
  (int, int)? point = (10, 20);

  if (point case (int x, int y) when x == y) {
    print("xとyが同じ: ($x, $y)");
  } else if (point case (int x, int y) when x > y) {
    print("xの方が大きい: ($x, $y)");
  } else if (point case (int x, int y)) {
    print("yの方が大きい: ($x, $y)");
  }
}
// switch + whenの例
void main() {
  int score = 85;
  switch (score) {
    case var s when s % 2 == 0:
      print("偶数のスコア: $score");
      break;
    case var s when s % 2 != 0:
      print("奇数のスコア: $score");
      break;
  }
}

9-3. 名前付きコンストラクタ

Dartでは、通常のコンストラクタとは別にクラス名.名前でコンストラクタ定義し、使い分けられる。

class Employee {
  String name;
  int age;
  String position;

  // 通常のコンストラクタ
  Employee(this.name, this.age, this.position);
  
  // 名前付きコンストラクタ(デフォルト値付き)
  Employee.guest() 
      : name = "ゲスト",
        age = 0,
        position = "未設定";

  void introduce() {
    print("名前: $name, 年齢: $age, 役職: $position");
  }
}

void main() {
  var guest = Employee.guest();
  guest.introduce(); // 名前: ゲスト, 年齢: 0, 役職: 未設定
}

9-4. factoryコンストラクタ

毎回新しいインスタンスを生成する必要がない場合に使用する。

class Employee {
  final String name;
  final int age;
  final String position;

  // プライベートコンストラクタ
  Employee._internal(this.name, this.age, this.position);

  // キャッシュ用 Map
  static final Map<String, Employee> _cache = {};

  // factoryコンストラクタ
  factory Employee(String name, int age, String position) {
    // すでに同じ名前のEmployeeがあれば再利用
    if (_cache.containsKey(name)) {
      print("既存のインスタンスを返します");
      return _cache[name]!;
    }

    // 新しいインスタンスを生成してキャッシュ
    final emp = Employee._internal(name, age, position);
    _cache[name] = emp;
    print("新しいインスタンスを生成しました");
    return emp;
  }

  void introduce() {
    print("名前: $name, 年齢: $age, 役職: $position");
  }
}

9-5. 拡張メソッド

既存のクラスに新しいメソッドを追加できる機能

extension StringExtensions on String {
  // 文字列を逆順にするメソッド
  String reversed() {
    return split('').reversed.join();
  }
}

void main() {
  String text = "Hello";
  print(text.reversed()); // olleH
}

10. まとめ

とりあえずDartを触ってみて、個人的に気になった部分をまとめてみました。
(まだ学習途中なので抜けや誤りがあるかもしれません…)

特に印象的だったポイント:

  • null安全がデフォルトで組み込まれている(?, !, ??など)
  • constfinalの使い分けが混乱するけど、慣れると便利そう
  • 名前付き引数や拡張メソッドなどの機能が便利そう

Javaと比較するためにJavaについても改めて調べてみたのですが、そちらもまだまだたくさん勉強するところがあると感じました。
これからFlutterで実際にアプリを作りながら、もっと理解を深めていきたいと思います。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?