今回は、Javaスコープについての考え方や実装時に知っておくべきことご紹介します。スコープはJavaを学び始めた時には意識することが少ないですが、実際の開発現場ではとても大切な事です。
スコープを適切に設定することによって影響範囲を絞ることができるので、改修やメンテナンスをする時のエンジニアの負担が減るからです。今回の記事を参考にスコープについての知識を深めてみてください。

スコープはエンジニアにとって不可欠とも言えるものやで!
記事の信頼性:元教員の現役エンジニアの「しう」がJavaのスコープについて書いています。実際の開発現場でもスコープを意識して開発しています。
スコープとは?【Java】
スコープとは影響範囲のことです。IT業界では影響範囲のことをスコープとカッコよく呼び、変数のスコープと言われた場合は、その変数を扱える範囲のことになります。例えば、スコープの外で変数を扱おうとするとコンパイルエラー(文法的にダメと言われる)になります。
慣れてきたらある程度スコープを意識せずに実装を進めることができますが、初めのうちはスコープを明確にして実装しておきましょう。
変数のスコープ(ローカル、static、インスタンス)
変数のスコープについて次の順番で解説をしていきます。変数のスコープには次の3種類があり、それぞれ扱える範囲が異なるので見ていきましょう。
- ローカル変数
- static変数
- インスタンス変数
ローカル変数
1つ目に解説する変数はローカル変数です!
{}のことをブロックといいますが、そのブロック内で扱うことができる変数をローカル変数と言います。クラス・メソッドやif文、for文でも使われます。
ローカル変数の具体例としては次のようになります。
public class Local {
public static void main(String[] args) {
String localVariable = “ローカル変数”;
for (int i = 0: i < 2: i++) {
String word = “単語”
System.out.println(localVariable);
System.out.println(word);
}
System.out.println(localVariable); // localVariableはスコープ内なのでエラーにならない
System.out.println(word); // wordはスコープ外なのでエラーになる
}
}
上の例ではローカル変数としてlocalVariable、i、wordが出てきました。localVariableはmainメソッド内であれば問題なく使えますが、iとwordについてはfor文内のローカル変数なので、for文の外では使うことができません。変数を使う場合は、スコープを意識することが大切だということがわかりますね。
インスタンス変数
2つ目に解説する変数はインスタンス変数です!
インスタンス変数はクラスをインスタンスしてから利用することができます。クラスを作成するたびに異なるインスタンス変数を利用することができます。具体例としては次のようになります。
public class Instance {
String instanceVariable = “インスタンス変数”;
public void display(){
System.out.println(“表示名:” + instanceVariable );
}
}
public class InstanceMain {
public static void main(String[] args) {
Instance instanceFirst = new Instance();
Instance instanceSecond = new Instance();
instanceSecond.instanceVariable = "上書き後のインスタンス変数";
instanceFirst.display();
instanceSecond.display();
}
}
先ほど紹介したローカル変数をInstanceクラス内に定義します。Mainクラス内でインスタンス化することでインスタンス変数として利用することができます。
インスタンス化したinstanceFirst, instanceSecondのインスタンス変数instanceVariableには“インスタンス変数”の文字列が入っています。instanceSecondを上書きして、”上書き後のインスタンス変数”としてdisplayメソッドを実行しています。
instanceFirstのdisplayメソッドは上書きされていないinstanceFirst. instanceVariableを利用しているので“インスタンス変数”と表示されますが、instanceSecondのdisplayメソッドは上書きされているinstanceSecond. instanceVariableを利用しているため”上書き後のインスタンス変数”と表示されます。
このようにインスタンス変数ではインスタンス化した回数分変数が作成されます。ちなみにインスタンス化せずにinstanceVariableを利用しようとするとコンパイルエラーとなるので気を付けてください。



クラスが設計書(型抜き)で、インスタンス化は設計書(型抜き)からものを作成するイメージでいいで!
static変数
3つに解説する変数はstatic変数です!
static変数は先ほど紹介したインスタンス変数と異なりインスタンス化せずに利用することができます。クラス名.static変数名と書くことでstatic変数は利用できます。具体例としては次のようになります。
public class Static {
public static String staticVariable = “スタティック変数”;
}
public class StaticMain {
public static void main(String[] args) {
System.out.println(Static.staticVariable.);
}
インスタンス変数と異なり、static変数はStatic.staticVariableと書くことで利用できていますね。複数のクラスで利用される定数などはstatic変数として変数を定義することが実際の開発現場では多いです。
慣れてきたらstatic変数とインスタンス変数ではメモリ管理のされ方が異なるなどの知識も学んでみてください。
アクセス修飾子でスコープを設定
スコープには変数だけでなく、アクセス修飾子についての知識も大切です。アクセス修飾子によってどのスコープで呼び出すことが可能なのかが異なるからです。
Javaのアクセス修飾子には次の4つがあります。
アクセス修飾子 | 概要 |
---|---|
public | すべてのクラスからアクセスできる |
protected | 現在のクラスとサブクラスからアクセスできる |
なし(package private) | 現在のクラスと同じパッケージのクラスからアクセスできる |
private | 現在のクラスからだけアクセスできる |
また、「良いコード悪いコードで学ぶ設計入門」には次のような記載もあります。
保守性(メンテナンス性)を高めるために、クラス同士の依存関係はなくした方がいいという考え方があります。(BクラスがないとAクラスを利用できない時、BクラスはAクラスに依存している(密結合である)といいます)
依存関係を少なくするためにもアクセス修飾子はデフォルトのpackage privateを利用して、スコープを狭くすることが大切です。
ローカル変数をスコープ外で利用したい時
実際の開発現場で働いているとローカル変数をスコープ外で利用したい時が出てきます。複数の条件でデータベースから取得した時に、一つ一つの検索結果をfor文の外で利用したい時などです。その時に筆者の「しう」がどのように書けば適切か悩んだので、この記事にて記録を残しておきます。
次の2つの方法について解説していきます。(先輩エンジニアからは2つ目のラムダ式を活用する方法を採用した方がいいとアドバイスをもらいました)
- スコープ外で変数を定義
- ラムダ式を活用する
スコープ外で変数を定義
1つ目の方法は「スコープ外で変数を定義」です!
この方法はJava初心者が一番思いつく方法で理解がしやすい方法だと思います。具体的な方法としては次のようになります。
public class Main {
public static void main(String[] args) {
int count = 0;
for(int i = 1; i < 5; i++) {
count = count + 2;
}
System.out.println(count);
}
}
for文で4回繰り返していますが、毎回countに2を足しています。for文のスコープ外に定義したcountに足すことでfor文の外でも足していった結果を利用することができます。
ただし、この方法では変数(count)の値を変えていくことが必要で、(案件によっては)不適切な書き方とされています。
(※一度定義した変数の値は変えることなく実装することがいいとされていて、変数の値を変える必要がある場合は新しくクラスをインスタンス化するなどする方法が推奨されています。できるだけ変数でなく定数を使うことで、変数の中身が入れ替わっている個所を探す手間をなくしましょうという趣旨です。)
ラムダ式を活用する
2つ目の方法は「ラムダ式を活用する」です!
ラムダ式はJava8から利用できるようになりましたが、ラムダ式を活用してスコープ外でも変数を利用する方法があります。(厳密にはスコープ外で変数を利用しているわけでなありませんが、表現が難しかったためこのような書き方にしています)
具体的な方法は次のようになります。少し複雑ですが解説もしていきます。
public class Name {
String name;
}
public class Names {
List<Name> names;
}
public class NameId {
int nameId;
}
public class NameCondition {
List<NameId> nameIds;
}
public class Main {
public static void main(String[] args) {
var NameCondition = new NameCondition();
・・・(省略)・・・
var names = new Names(NameCondition.getNameIds().stream().map(
nameId -> {
var selectName = repository.select(nameId);
return selectName.getName();
}
).toList());
}
}
Name, Names, NameId, NameConditionクラスを準備として作成をしています。NameConditionクラスは名前を検索する条件を設定するクラスです。
MainクラスではNameConditionクラスを利用して、条件を設定しています。そして、その検索条件(NameCondition)からnameIdsを取得して、各nameIdに対してrepository.selectを利用してデータベースから該当するnameを取得しています。取得したnameをreturnの部分で返して、リストにしたものをnamesとしています。
(repositoryは割愛していますが、データベースとの役割を担っているクラスとしています)
この方法はラムダ式を利用した書き方やドメイン駆動設計になじみがない場合はややこしく感じるかもしれません。しかし、案件によっては今回紹介した実装方法が推奨されることもあるので、頭の片隅でも入れておくことは大切です。
まとめ
いかがでしたか?今回は、次の順番でJavaのスコープについて解説しました。
- Java・スコープとは?
- 変数のスコープ(ローカル、static、インスタンス)
- アクセス修飾子
- ローカル変数をスコープ外で利用したい時
スコープはJavaを学び始めたばかりの時はあいまいに実装をしてしまうことが多いです。しかし、実際の開発現場でコードを書く場合、スコープをはっきりさせておくことの大切さがわかります。
スコープを絞っておくことで影響範囲が明確になり、改修時に考慮する範囲が狭くなってエンジニアの負担が減るからです。ある程度開発に慣れてきたタイミングでスコープも意識して開発できるように工夫をしてみてくださいね。
ちなみに、スコープやコードの書き方については次の書籍がオススメです。(筆者のしうもこの書籍で基本的な実装時のお作法については学びました)
☟あわせて読みたい 「しう」のオススメブログ


【しうの備忘録】-300x200.png)
【しうの備忘録】-300x200.png)
関数型インターフェース-300x200.png)
関数型インターフェース-300x200.png)
コメント