M.Hiroi's Home Page
http://www.geocities.jp/m_hiroi/

お気楽 Java プログラミング入門

第 1 回 Java の基礎知識 (1)

[ PrevPage | Java | NextPage ]

はじめに

Java は 1990 年代前半にサン・マイクロシステムズで開発されたオブジェクト指向プログラミング言語です。プログラミングに興味のある方ならば、Java をまったく知らないという人はほとんどいないと思います。最初期のころはとても遅かった Java ですが、JIT (Just in Time) コンパイラなどの技術により性能は大きく改善され、今では様々な分野で使われるようになりました。

最近は JavaScript, PHP, Perl, Python, Ruby などのスクリプト言語に注目が集まっていますが、JVM (Java 仮想マシン) 上で動作するスクリプト言語も開発されています。有名なところでは Groovy, Rhino (JavaScript), Jython (Python), JRuby (Ruby) があります。また、関数型言語では Kawa (Scheme) や Clojure などの Lisp 系の言語や、ML のように型推論を行う Scala もあります。

これらのスクリプト言語は Java のライブラリ資産を簡単に利用することができます。また、時間のかかる処理を Java で作成し、それをスクリプト言語から呼び出すことで、プログラムの処理を高速化することもできます。Java の膨大なライブラリ資産を活用できるのは大きなメリットですし、Java とスクリプト言語で役割を分担することで、柔軟なプログラミングが可能になると思われます。

このように、Java はプログラミング言語というよりも、いろいろな言語を実行するためのプラットフォームになりつつあります。もちろん、その中心には Java があるわけで、Java を理解しておくと、他のスクリプト言語を使うときにも役に立つと思います。M.Hiroi は Java に関して初心者にすぎません。このページで簡単なプログラムを作りながら Java を勉強していきたいと思っております。たいしたことはできませんが、よろしければお付き合いくださいませ。

●Java のプログラム

Java はC言語やC++とよく似ています。プログラムの実行を制御する「文」、データを格納する「変数」、決められた処理を行う「関数」(Java ではメソッド) があります。Java はオブジェクト指向プログラミング言語なので、クラス (class)、インスタンス (instance)、メソッド (method)、継承 (inheritance) などのオブジェクト指向機能があります。このほかにも例外処理やマルチスレッドといった高度な機能もサポートされています。

Java にはいろいろなデータが用意されています。データの種類を「データ型 (Data type) 」と呼びます。Java はオブジェクト指向機能を使って多数のデータ型とそれを操作するメソッドがライブラリ (Java ではパッケージ) に用意されています。数、配列、文字列などの基本的なデータ型をはじめ、リスト、ハッシュなどといった高水準なデータ型も用意されています。

Java のプログラムで使用される変数や関数などの名前には、英数字とアンダースコア _ が使えます。英大文字と英小文字は区別されるので、FOO と Foo と foo は異なる名前と判断されます。また、C/C++ と同様に文の最後はセミコロン ( ; ) で区切ります。コメントもC++と同じで、/* と */ で囲むか // から行末までになります。

●名前の付け方

名前の付け方ですが、Java では「キャメル記法 (camelcase)」を用いるのが一般的なようです。キャメル記法は複数の単語をひと綴りにして、単語ごとに最初の文字を英大文字で表します。このとき、2 通りの方法があります。

upper camelcase は「パスカル記法」と呼ばれることもあります。本稿ではクラス名を upper camelcase で、関数 (メソッド) や変数の名前は lower camelcase で記述することにします。ただし、簡単なサンプルプログラムのように、クラス名にあまり意味がない場合は sample + 数字 にしています。あしからずご了承ください。

●プログラムの実行

Java の開発環境はいくつかありますが、このページでは最も基本的な Java SE Development Kit (JDK) を使います。現時点 (2016 年 11 月) での最新バージョンは JDK 8 です。Java のインストールは Javaをインストールするには をお読みください。

それではお馴染みの Hello, World! を表示するプログラムを作ってみましょう。次のリストを見てください。

リスト 1 : Hello.java

public class Hello {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
  }
}

ファイル名は Hello.java とします。拡張子は java で、ファイル名は public 宣言したクラスの名前 Hello と同じにしてください。Java はオブジェクト指向プログラミング言語なので、クラスを定義しないとプログラムを作ることができません。ここで簡単にクラス、インスタンス、メソッドについて説明しておきましょう。

クラスはオブジェクトの設計図にあたるもので、オブジェクトの「雛形」と呼ぶこともあります。このクラスから実体として作り出されるのがインスタンスです。このインスタンスを「オブジェクト」と考えてください。インスタンスを生成する方法は、当然ですがプログラミング言語によって違います。たとえばC++や Java は new を使います。

Java の場合、メソッドはクラスの中で定義します。一般に、メソッドはインスタンスを操作するための関数で、メソッドを呼び出すにはインスタンスが必要になります。これに対し、インスタンスを必要としないメソッドを定義することができます。これをクラスメソッドとかスタティックメソッドといいます。クラスメソッドはインスタンスがなくても呼び出すことができます。クラス自身を操作する場合や関数のようなメソッドを定義する場合に使います。

Java の場合、メソッドの定義に static を付けるとクラスメソッドになります。main はクラスメソッドで、C/C++の main 関数と同様にプログラムの実行は main メソッドから始まります。main の引数 args にはコマンドラインで与えられた引数が格納されています。System.out.println() はデータを標準出力 (画面) へ出力するメソッドです。

オブジェクト指向についてはあとで詳しく説明しますが、とりあえずプログラムを作るには public 宣言したクラスと main メソッドが必要である、ということを覚えておいてください。

プログラムのコンパイルは javac で行います。Windows の場合、コマンドプロンプトで javac Hello.java と入力すると、Hello.java がコンパイルされて Hello.class というファイルが作成されます。

C>javac Hello.java

C>dir /B Hello.*
Hello.class
Hello.java

C>java Hello
Hello, World!

C>

プログラムの実行は java を使います。コマンドプロンプトで java Hello と入力します。クラス Hello のメソッド main が呼び出されて Hello, World! が表示されます。

●ソースファイルの文字コード

Windows の場合、プログラムを書くときに Shift JIS 以外の文字コードを使うと、javac でコンパイルエラーになります。

エラー: この文字は、エンコーディングMS932にマップできません

Shift JIS 以外の文字コードを使う場合はオプション -encoding で文字コードを指定してください。たとえば、UTF-8 ならば javac -encoding utf-8 ソースファイル とします。ご注意くださいませ。

●整数と浮動小数点数

Java は標準で整数 (integer) と浮動小数点数 (floating point number) を使うことができます。表 1 に整数と浮動小数点数の種類を示します。

表 1 : 整数と浮動小数点数
型名範囲
byte-128 ~ 127 (8 bit)
short-32768 ~ 32767 (16 bit)
int-2147483648 ~ 2147483647 (32 bit)
long-9223372036854775808 ~ 9223372036854775807 (64 bit)
float±1.1754944E-38 ~ 3.4028235E+38 (32 bit 単精度)
double±2.22507E-308 ~ 1.79769E+308 (64 bit 倍精度)

さっそく簡単な例を示しましょう。次のリストを見てください。

リスト 2 : 数と四則演算

public class sample10 {
  public static void main(String[] args) {
    int a = 20;
    int b = 10;
    double c = 1.234;
    double d = 5.678;
    System.out.println(a + b);
    System.out.println(a - b);
    System.out.println(c * d);
    System.out.println(c / d);
  }
}
C>java sample10
30
10
7.006652
0.2173300457907714

Java はC/C++と同様に、あらかじめ使用する変数とそのデータ型を宣言する必要があります。変数の定義は次のように行います。

データ型 変数名1, 変数名2, ..., 変数名N;
データ型 変数名1 = 初期値1, 変数名2 = 初期値2, ..., 変数名N = 初期値N;

まず最初にデータ型を指定して、その後ろに変数を表す名前を書きます。同じデータ型であれば、カンマ ( , ) で区切って複数の変数を定義することができます。このとき、同時に初期値をセットすることができます。これを変数の初期化といいます。また、変数に値をセットすることを「代入」といい、代入には = を使います。

値は関数 System.out.println() または System.out.print() を使って表示することができます。print(), println() はパッケージ java.lang の System クラスに定義されているメソッドです。パッケージを利用する場合、import 文で宣言する必要がありますが、java.lang は自動的にインポートされるパッケージなので、import 文なしで利用することができます。データを画面へ出力したあと、println() は改行しますが print() は改行しません。

変数 a, b には整数を、変数 c, d には浮動小数点数を代入します。そして、演算結果を println() で表示します。主な算術演算子を表 2 に示します。

表 2 : 算術演算子
演算子操作
-x x の符号を反転
x + y x と y の和
x - y x と y の差
x * y x と y の積
x / y x と y の商
x % y x と y の剰余

●文字

Java には文字を表すデータ型 char が用意されています。C/C++とは異なり、Java の char は無符号 16 bit 整数 (0 - 65535) で、16 bit の Unicode になります。文字はシングルクオート ( ' ) で囲んで表します。文字を数値で記述する場合は '\uXXXX' のように 4 桁の 16 進数を使います。

●文字列

文字列 (string) はダブルクオート " で囲んで表します。Java の文字列はC/C++と違って、文字型の配列ではありません。String というクラスのインスタンスとして扱われます。クラス、インスタンスについてはオブジェクト指向を取り上げるときに詳しく説明します。簡単な例を示しましょう。

リスト 3 : 文字列

public class sample11 {
  public static void main(String[] args) {
    String a = "abcd";
    String b = "efgh";
    String c = a + b;
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
  }
}
C>java sample11
abcd
efgh
abcdefgh

文字列を表すデータ型は String です。Java はC++と同様にクラス名でデータ型を表します。変数 a と b に文字列をセットします。文字列は演算子 + を使って連結することができます。この場合、変数 c には "abcd" と "efgh" を連結した新しい文字列 "abcdefgh" がセットされます。

演算子 + は文字列を連結するとき、左右どちらかのデータが文字列ではない場合、そのデータを文字列に変換してから連結します。たとえば、1 + 1 は整数の足し算で値は 2 になりますが、1 + "1" は 1 を文字列に変換して連結するので "11" になります。

また、文字列には「エスケープシーケンス」を含めることができます。これは、画面に表示することができない文字を表すのに用いられる方法です。よく使われる記号に改行を表す \n とタブを表す \t があります。

●if 文

Java の制御構造はC/C++とほとんど同じです。最初に if 文から説明します。if 文は「条件分岐」を行います。簡単にいうと「もしも~~ならば○○をせよ」という動作です。図 1 を見てください。

      ↓                        ↓
┌─────┐No          ┌─────┐No
│  条  件  │─┐        │  条  件  │─────┐
└─────┘  │        └─────┘          │
      ↓Yes     │              ↓Yes             ↓
┌─────┐  │        ┌─────┐    ┌─────┐
│  処理A  │  │        │  処理A  │    │  処理B  │
└─────┘  │        └─────┘    └─────┘
      │        │              │                │
      ├←───┘              ├←───────┘
      ↓                        ↓

     (1)                        (2)

             図 1 : if 文の動作

図 1 (1) では、「もしも条件を満たすならば、処理 A を実行する」となります。この場合、条件が成立しない場合は何も処理を実行しませんが、図 1 (2) のように、条件が成立しない場合でも処理を実行させることができます。(2) の場合では、「もしも条件を満たすならば、処理 A を実行し、そうでなければ処理 B を実行する」となります。すなわち、条件によって処理 A か処理 B のどちらかが実行されることになります。

一般に、プログラミング言語では、条件が成立することを「真 (true)」といい、条件が不成立のことを「偽 (false) 」といいます。実際のプログラムでは真偽を表すデータが必要になります。Java の場合、真偽を表すデータ型 boolean が用意されていて、真を true で、偽を false で表します。C/C++ のように偽を 0 で表し、それ以外の値を真とすることはできません。ご注意ください。

図 2 に if 文の構文を示します。

if (test) {
  処理A;
  処理B;
  処理C;
} else {
  処理D;
  処理E;
  処理F;
}

図 2 : if の構文 (1)

条件部 test を実行し、その結果が真であれば、処理A から処理C を実行します。{ } で囲まれた部分を「ブロック」と呼び、ここに複数の処理を書くことができます。test の結果が偽であれば、else から始まるブロックで書かれている処理D から処理F を実行します。 else ブロックは省略することができます。また、ブロック内の処理が一つしかない場合は { } を省略することができます。

もう少し複雑な使い方を紹介しましょう。

if (testA) {
  処理A;
} else {
  if (testB) {
    処理B;
  } else {
    処理C;
  }
}

図 3 : if 文の入れ子
      ↓
┌─────┐No
│  testA   │─────┐
└─────┘          │
      ↓Yes             ↓
      │          ┌─────┐No
      │          │  testB   │─────┐
      │          └─────┘          │
      │                ↓Yes             ↓
┌─────┐    ┌─────┐    ┌─────┐
│  処理A  │    │  処理B  │    │  処理C  │
└─────┘    └─────┘    └─────┘
      │                │                │
      ↓                ↓                ↓
      ├────────┴────────┘
      ↓

         図 4 : if 文の入れ子の動作

testA が偽の場合は else 節を実行します。else 節は if 文なので、条件 testB を実行します。この結果が真であれば処理 B を実行します。そうでなければ、else 節の処理 C を実行します。この処理は図 5 のように書き換えることができます。

if (testA) {
  処理A;
} else if (testB) {
  処理B;
} else {
  処理C;
}

図 5 : if の構文 (2)

C/C++ と同様に eles if を使って if 文を連結することができます。testA が偽の場合は、次の else if の条件 testB を実行します。この結果が真であれば処理 B を実行します。そうでなければ、else 節の処理 C を実行します。なお、else if はいくつでも繋げることができます。

●比較演算子と論理演算子

Java には表 3 に示す比較演算子が用意されています。

表 3 : 比較演算子
演算子意味
== 等しい
!= 等しくない
< より小さい
> より大きい
<= より小さいか等しい
>= より大きいか等しい

C/C++の比較演算子と同じです。また、表 4 に示す論理演算子があります。

表 4 : 論理演算子
操作意味
!x x の否定(真偽の反転)
x && y x が真かつ y が真ならば真
x || y x が真まはた y が真ならば真

C/C++とは異なり、x, y は boolean 型のデータでなければいけません。&& は左項が偽ならば右項を評価せずに偽を返します。|| は左項が真ならば右項を評価せずに左項の値を返します。このため、&& と || は「短絡演算子」と呼ばれることもあります。

●三項演算子

Java はC/C++と同じく三項演算子 ? : を使うことができます。三項演算子の構文を示します。

条件式 ? 真の場合の式 : 偽の場合の式

簡単な例を示しましょう。

// if 文
if (条件式) {
  a = 式1;
} else {
  a = 式2;
}

// 三項演算子
a = 条件式 ? 式1 : 式2;

このように三項演算子を使うとプログラムを簡潔に記述できる場合があります。

●while 文による繰り返し

繰り返しは同じ処理を何度も実行することです。まずは簡単な繰り返しから紹介しましょう。while 文は条件が真のあいだ、ブロックに書かれている処理を繰り返し実行します。

while (test) {
  処理A;
  処理B;
  処理C;
}

図 6 : while 文の構文
              ↓
              ├←─────┐
  false ┌─────┐      │
┌───│  条件部  │      │
│      └─────┘      │
│            ↓true        │
│      ┌─────┐      │
│      │  処理A  │      │
│      └─────┘      │
│            ↓            │
│      ┌─────┐      │
│      │  処理B  │      │
│      └─────┘      │
│            ↓            │
│      ┌─────┐      │
│      │  処理C  │      │
│      └─────┘      │
│            ↓            │
│            └──────┘
└──────┐
              ↓

     図 7 : while 文の動作

図 6, 7 を見ればおわかりのように、while 文はいたって単純です。この動作はC/C++と同じです。なお、処理が一つしかない場合は { } を省略することができます。

簡単な例を示しましょう。Hello, World! を 10 回表示するプログラムをリスト 4 に示します。

リスト 4 : hello. wolrd の表示

public class sample12 {
  public static void main(String[] args) {
    int i = 0;
    while (i < 10) {
      System.out.println("Hello, World!");
      i += 1;
    }
  }
}
C>java sample12
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!

変数 i を 0 に初期化し、i の値が 10 よりも小さいあいだ処理を繰り返します。C/C++と同様に、i += 1 は i = i + 1 と同じ意味です。このほかに、-=, *=, /=, %= などがあります。i の値はブロックを実行するたびに +1 されていくので、i が 10 になった時点で繰り返しを終了します。

while 文には do { ... } while (test); という形式もあります。これはブロックの処理を実行してから条件部をチェックします。したがって、ブロックの処理は最低でも 1 回は必ず実行されます。リスト 4 のプログラムを書き直すと、次のようになります。

リスト 5 : hello, world の表示 (2)

public class sample13 {
  public static void main(String[] args) {
    int i = 0;
    do {
      System.out.println("Hello, World!");
      i += 1;
    } while (i < 10);
  }
}

これでも hello, world を 10 回表示することができます。

●インクリメント演算子とデクリメント演算子

Java には値を 1 増やすインクリメント演算子 ++ と値を 1 減らすデクリメント演算子 -- があります。これはC/C++と同じ働きをする演算子です。演算子を前に置くと、値を更新してから式を評価します。後ろにおいた場合は式を評価してから値を更新します。次の例を見てください。

リスト 6 : インクリメント演算子

public class sample14 {
  public static void main(String[] args) {
    int i = 1, j = 10;
    int x = ++i;
    int y = j++;
    System.out.println(i);
    System.out.println(j);
    System.out.println(x);
    System.out.println(y);
  }
}
C>java sample14
2
11
2
10

変数 x, y に値をセットするとき、変数 i, j の値を +1 しています。このため、i, j の値は 2 と 11 になります。x の値は演算子 ++ が i の前についているので、i の値を +1 してから、i の値を x に代入します。このため、x の値は 2 になります。逆に、y の値は演算子 ++ が j の後ろに付いているので、j の値を y に代入してから j の値を +1 します。したがって、y の値は 10 になるのです。

簡単な例として、1 から 1000 までの総和を求めてみましょう。

リスト 7 : 1 から 1000 までの総和

public class sample15 {
  public static void main(String[] args) {
    int i = 1, sum = 0;
    while (i <= 1000) sum += i++;
    System.out.println(sum);
  }
}
C>java sample15
500500

変数 i を 1 に、総和を表す変数 sum を 0 に初期化します。while 文で i の値を sum に加えてから、i の値を +1 します。この処理は sum += i++; と表すことができます。++ を i の後ろにつけることで、i の値を sum に加えてから、i の値を +1 することができます。++i とすると正しい値にはなりません。このように、++ と -- はとても便利な演算子ですが、使うときには十分に注意してください。

●FizzBuzz 問題

もう一つ簡単な例題として FizzBuzz 問題を Java で解いてみましょう。FizzBuzz 問題は 1 から 100 までの値を表示するとき、3 の倍数のときは Fizz を、5 の倍数ときは Buzz を表示するというものです。FizzBuzz 問題の詳細については Fizz Buzz - Wikipedia をお読みください。

プログラムは次のようになります。

リスト 8 : FizzBuzz 問題

public class FizzBuzz {
  public static void main(String[] args) {
    int i = 1;
    while (i <= 100) {
      if (i % 3 == 0 && i % 5 == 0) {
        // 15 の倍数
        System.out.print("FizzBuzz");
      } else if (i % 3 == 0) {
        // 3 の倍数
        System.out.print("Fizz");
      } else if (i % 5 == 0) {
        // 5 の倍数
        System.out.print("Buzz");
      } else {
        // 数字をそのまま表示
        System.out.print(i);
      }
      if (i % 20 == 0) {
        System.out.println();
      } else {
        System.out.print(" ");
      }
      i++;
    }
  }
}
C>java FizzBuzz
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz
41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz
61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz
Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz

変数 i を 1 に初期化し、while 文の中で 1 ずつ増やしていきます。最初の if 文で、i が 3 の倍数でかつ 5 の倍数かチェックします。この処理は 15 の倍数をチェックすることと同じなので、条件文を i % 15 == 0 としてもかまいません。そうでなければ、次の else if で i が 3 の倍数かチェックし、次の else if で i が 5 の倍数かチェックします。どの条件も該当しない場合は最後の else 節で i をそのまま出力します。

今回はここまでです。次回は配列を中心に Java の基本的な機能について説明します。

初版 2009 年 4 月 4 日
改訂 2016 年 11 月 12 日

Copyright (C) 2009-2016 Makoto Hiroi
All rights reserved.

[ PrevPage | Java | NextPage ]