この記事は 2026 年 8 月 20 日に投稿しました。

目次
- はじめに
- DartのHashSetから指定した位置の要素を安全に取得する
- elementAtOrNullメソッドとelementAtメソッドの違い
- 範囲外のインデックスを指定した場合
- elementAtOrNullメソッドを使用する場合の注意点
- おわりに
1. はじめに
こんにちは、iOS のエディタアプリPWEditorとその後継PWEditorNextの開発者の二俣です。
2018年5月から毎日技術ブログを更新しています。
今回はDartのHashSetから、指定したインデックスの要素を安全に取得できるelementAtOrNullメソッドについてです。
2. DartのHashSetから指定した位置の要素を安全に取得する
DartのHashSetでは、elementAtOrNullメソッドを使用すると、反復順序における指定したインデックスの要素を取得できます。
elementAtOrNullメソッドの形式は以下になります。
T? elementAtOrNull(int index)
引数indexに、取得したい要素のインデックスを指定します。
インデックスは0から始まります。
例えば、次のHashSetがあるとします。
final languages = HashSet<String>(); languages.addAll([ 'Dart', 'Flutter', 'Swift', ]);
elementAtOrNullメソッドを使用すると、次のように要素を取得できます。
final language = languages.elementAtOrNull(0);
print(language);
この場合、HashSetの反復順序で最初に位置する要素が取得されます。
戻り値の型はString?となり、指定した位置に要素が存在しない場合はnullが返されます。
実装例
import 'dart:collection'; void main() { final languages = HashSet<String>(); languages.addAll([ 'Dart', 'Flutter', 'Swift', ]); final language = languages.elementAtOrNull(0); print(language); }
elementAtOrNullメソッドの特徴は、指定したインデックスが要素数以上だった場合に、例外ではなくnullを返すことです。
例えば、
final language = languages.elementAtOrNull(10);
print(language);
とした場合、要素数が10個以下であれば、
null
となります。
そのため、
if (index < languages.length) { final language = languages.elementAt(index); }
のように、あらかじめ要素数を確認しなくても、指定した位置に要素が存在するかどうかを戻り値で判断できます。
例えば、
final language = languages.elementAtOrNull(10); if (language != null) { print(language); } else { print('要素がありません'); }
とできます。
ただし、ここで注意したいのが、HashSetでは要素の順序が保証されていないという点です。
例えば、
languages.elementAtOrNull(0)
としたからといって、最初に追加したDartが必ず取得できるわけではありません。
HashSetは順序を管理するためのコレクションではなく、要素の反復順序は規定されていません。
そのため、elementAtOrNullメソッドは、
追加した順番の0番目の要素を取得する
という意味ではなく、
現在の反復順序における0番目の要素を取得する
と考える必要があります。
また、elementAtOrNullメソッドはIterableExtensionsで提供されているメソッドです。
HashSetだけでなく、ListなどのIterableでも利用できます。
例えば、
final languages = [ 'Dart', 'Flutter', 'Swift', ]; print(languages.elementAtOrNull(1)); print(languages.elementAtOrNull(10));
とすると、
Flutter null
となります。
3. elementAtOrNullメソッドとelementAtメソッドの違い
elementAtOrNullメソッドと似たメソッドに、elementAtメソッドがあります。
どちらも、反復順序における指定したインデックスの要素を取得するために使用できます。
例えば、
final value1 = set.elementAt(1); final value2 = set.elementAtOrNull(1);
のように使用します。
指定したインデックスに要素が存在する場合は、どちらもその位置の要素を取得できます。
大きな違いは、指定したインデックスに要素が存在しない場合の動作です。
elementAtメソッドでは、範囲外のインデックスを指定するとエラーになります。
一方、elementAtOrNullメソッドでは、要素が存在しない場合にnullが返されます。
例えば、次のHashSetがあるとします。
final set = HashSet<String>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]);
要素数は3なので、有効なインデックスは、
0 1 2
です。
ここで、
final value = set.elementAtOrNull(3);
print(value);
とすると、
null
が表示されます。
そのため、インデックスが範囲外になる可能性がある場合は、elementAtOrNullメソッドを使用することで処理を簡潔にできます。
例えば、elementAtメソッドでは、
String? value; if (index >= 0 && index < set.length) { value = set.elementAt(index); }
のように範囲を確認する必要があります。
インデックスが負にならないことが保証されている場合、elementAtOrNullメソッドなら、
final value = set.elementAtOrNull(index);
と記述できます。
取得できたかどうかは、
if (value != null) { print(value); } else { print('指定した位置に要素がありません'); }
のように判断できます。
また、null-aware演算子を組み合わせて、
final value = set.elementAtOrNull(index) ?? '要素なし'; print(value);
とすることもできます。
このように、指定位置に要素が存在しないことが通常の処理として起こり得る場合には、elementAtOrNullメソッドを利用すると便利です。
ただし、HashSetにnull自体を要素として格納している場合には注意が必要です。
例えば、
final set = HashSet<String?>(); set.addAll([ 'Dart', null, 'Swift', ]);
の場合、
final value = set.elementAtOrNull(index);
の戻り値がnullだったとしても、
指定した位置に要素が存在しなかった
のか、
指定した位置の要素自体がnullだった
のかを、戻り値だけでは区別できません。
nullを要素として持つコレクションで利用する場合は、この点も考慮する必要があります。
4. 範囲外のインデックスを指定した場合
elementAtOrNullメソッドでは、指定したインデックスが要素数以上の場合、nullが返されます。
例えば、要素数が3の場合に要素が存在するインデックスは、
0 1 2
です。
3以上を指定すると、その位置には要素が存在しないためnullが返されます。
例えば、
import 'dart:collection'; void main() { final set = HashSet<String>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]); final value = set.elementAtOrNull(3); print(value); }
この場合、
null
となります。
さらに大きなインデックスを指定しても同様です。
print(set.elementAtOrNull(100));
この場合も、
null
となります。
空のHashSetに対して使用した場合も同様です。
final set = HashSet<String>(); print(set.elementAtOrNull(0));
要素が存在しないため、
null
となります。
このため、例えば最初の要素が存在する場合だけ処理したい場合は、
final value = set.elementAtOrNull(0); if (value != null) { print(value); }
と記述できます。
ただし、elementAtOrNullメソッドを使用する場合でも、インデックスには負の値を指定できません。
例えば、
set.elementAtOrNull(-1);
のような指定は、
末尾から1番目の要素
という意味にはなりません。
elementAtOrNullメソッドのインデックスは0以上である必要があります。
そのため、変数をインデックスに使用し、その値が負になる可能性がある場合には、事前に確認が必要です。
例えば、
import 'dart:collection'; void main() { final set = HashSet<String>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]); const index = -1; final value = index >= 0 ? set.elementAtOrNull(index) : null; print(value); }
のようにできます。
つまり、elementAtOrNullメソッドは、
index >= length
の場合にはnullを返してくれますが、
index < 0
まで安全に扱うためのメソッドではない点に注意が必要です。
5. elementAtOrNullメソッドを使用する場合の注意点
HashSetでelementAtOrNullメソッドを使用する場合、特に注意したいのが要素の順序が保証されていない点です。
例えば、
import 'dart:collection'; void main() { final languages = HashSet<String>(); languages.add('Dart'); languages.add('Flutter'); languages.add('Swift'); print(languages.elementAtOrNull(0)); print(languages.elementAtOrNull(1)); print(languages.elementAtOrNull(2)); }
とした場合でも、
Dart Flutter Swift
という追加順で取得できることは保証されていません。
HashSetは順序を持たないSetであり、反復順序は規定されていません。
そのため、
final firstLanguage = languages.elementAtOrNull(0);
として、
最初に追加した言語
という意味で使用するべきではありません。
追加した順番を維持したい場合は、LinkedHashSetを利用する方法があります。
LinkedHashSetでは、要素は挿入順に反復されます。
例えば、
import 'dart:collection'; void main() { final languages = LinkedHashSet<String>(); languages.add('Dart'); languages.add('Flutter'); languages.add('Swift'); print(languages.elementAtOrNull(0)); print(languages.elementAtOrNull(1)); print(languages.elementAtOrNull(2)); }
の場合は、挿入順に、
Dart Flutter Swift
と取得できます。
一方、インデックスを利用した要素へのアクセスを頻繁に行うのであれば、SetではなくListを利用する方が適している場合もあります。
例えば、
final languages = [ 'Dart', 'Flutter', 'Swift', ]; print(languages[1]);
とすると、
Flutter
を取得できます。
Listはインデックスを使用して要素を扱うコレクションなので、
languages[1]
のような記述ができます。
一方、HashSetには、
set[1]
のようなインデックス演算子による要素取得はありません。
elementAtOrNullメソッドは、HashSetにインデックスが付与されているという意味ではなく、反復順序における指定位置の要素を取得するためのメソッドです。
また、単純にすべての要素を処理したいのであれば、インデックスを指定して繰り返し取得する必要はありません。
例えば、
for (final value in set) { print(value); }
のようにfor-inを使用した方が、処理の目的が分かりやすくなります。
elementAtOrNullメソッドは、
指定した位置に要素があれば取得したい
という場合に向いています。
例えば、
final value = set.elementAtOrNull(index); if (value != null) { // 要素が取得できた場合の処理 }
のような処理です。
また、順序を決めてから特定位置の要素を安全に取得したい場合は、Listへ変換して並べ替える方法もあります。
例えば、
import 'dart:collection'; void main() { final numbers = HashSet<int>(); numbers.addAll([ 30, 10, 40, 20, ]); final sortedNumbers = numbers.toList()..sort(); print(sortedNumbers.elementAtOrNull(0)); print(sortedNumbers.elementAtOrNull(1)); print(sortedNumbers.elementAtOrNull(10)); }
sortを実行した後は、
10 20 30 40
という順番になるため、
sortedNumbers.elementAtOrNull(0)
では10、
sortedNumbers.elementAtOrNull(1)
では20、
sortedNumbers.elementAtOrNull(10)
では、
null
となります。
このように、
順序は必要ないが重複を持たせたくない
場合はHashSet、
挿入順を維持したSetを使用したい
場合はLinkedHashSet、
インデックスによって要素を扱いたい
場合はList
というように、用途に合わせてコレクションを使い分けることも重要です。
なお、elementAtOrNullメソッドはHashSet固有のメソッドではありません。
IterableExtensionsによってIterableに提供されているため、HashSet以外のさまざまな反復可能オブジェクトでも使用できます。
リファレンス
IterableExtensions.elementAtOrNull
6. おわりに
DartのHashSetから、反復順序における指定した位置の要素を安全に取得するには、elementAtOrNullメソッドを使用できます。
例えば、
final set = HashSet<String>(); set.addAll([ 'Dart', 'Flutter', 'Swift', ]); final value = set.elementAtOrNull(0);
とすると、HashSetの反復順序で0番目にある要素を取得できます。
指定した位置に要素が存在しない場合は、
final value = set.elementAtOrNull(10);
としても、範囲外であれば例外ではなくnullが返されます。
そのため、
final value = set.elementAtOrNull(index); if (value != null) { print(value); }
のように、指定した位置に要素が存在する場合だけ処理するといった使い方ができます。
elementAtメソッドでは範囲外のインデックスを指定するとエラーになりますが、elementAtOrNullメソッドでは要素が存在しないことをnullとして扱える点が大きな違いです。
ただし、インデックスには負の値を指定できません。
変数をインデックスとして使用し、その値が負になる可能性がある場合は、事前に0以上であることを確認する必要があります。
また、HashSetでelementAtOrNullメソッドを使用する際に特に注意したいのが、要素の順序が保証されていないことです。
そのため、
set.elementAtOrNull(0)
で取得される要素を、
最初に追加した要素
と考えることはできません。
挿入順を維持したい場合はLinkedHashSet、インデックスによる要素の操作を中心に行いたい場合はListを使用することも検討するとよいでしょう。
elementAtOrNullメソッドは、反復可能なコレクションから指定した位置の要素を取得し、要素が存在しない場合もnullとして安全に扱いたい場合に便利なメソッドです。
私が技術者として所属している ニューラル では、 組み込み・制御系ソフトウェアを中心に、モバイルアプリや業務アプリなど、さまざまなソフトウェアの開発を行っています。
組み込み分野では、リアルタイムOSを利用したシステム開発をはじめ、弊社製品のハイブリッドOS Bi-OS など、長年培ってきた組み込み・制御系の技術を活かした開発に取り組んでいます。
また、iOS(Swift/SwiftUI)やWindows(C#)をはじめとしたアプリケーション開発、Webシステムの開発などにも対応しています。
組み込みソフトウェア、モバイルアプリ、Windowsアプリ、Webシステムなど、ソフトウェア開発に関するご相談がございましたら、お気軽にお問い合わせください。
また、ニューラルでは一緒にソフトウェア開発に取り組んでいただける技術者の方も募集しています。
ご興味がございましたら、お気軽にお問い合わせください。
EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688