M.Hiroi's Home Page

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

Java の基礎知識 (1)

[ PrevPage | Java | NextPage ]

はじめに

今回は Java の最も基本的なデータ型 (数と文字列) と簡単な制御構造 (if 文と while 文) について説明します。

●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 は標準で整数 (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 倍精度)

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

jshell> int a = 20
a ==> 20

jshell> int b = 10
b ==> 10

jshell> double c = 1.234
c ==> 1.234

jshell> double d = 5.678
d ==> 5.678

jshell> a
a ==> 20

jshell> b
b ==> 10

jshell> c
c ==> 1.234

jshell> d
d ==> 5.678

jshell> a + b
$7 ==> 30

jshell> a - b
$8 ==> 10

jshell> c * d
$9 ==> 7.006652

jshell> c / d
$10 ==> 0.2173300457907714

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

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

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

変数 a, b には整数を、変数 c, d には浮動小数点数を代入します。JShell は変数名を入力すると、変数に格納されている値を返します。式を入力すると、それをすぐに計算して結果を返します。主な算術演算子を表 2 に示します。

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

JShell で行った計算をプログラムすると次のようになります。

リスト : 数と四則演算

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);
  }
}
$ javac sample10.java
$ java sample10
30
10
7.006652
0.2173300457907714

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

ところで、JShell でソースファイルを読み込み、そのプログラムを実行することもできます。ソースファイルの読み込みは JShell のコマンド /open を使います。

/open filename
jshell> /open sample10.java

jshell> /types
|    class sample10

jshell> sample10.main(new String[] {})
30
10
7.006652
0.2173300457907714

/open sample10.java を実行すると、JShell はソースファイル sample10.java を読み込んでプログラムをコンパイルします。その結果、JShell の中にクラス sample10 が生成されます。/types は JShell 上で定義された型 (クラス) を表示するコマンドです。あとは sample10 の中に定義されている main() を呼び出せば、プログラムを実行することができます。

Java の場合、メソッドはクラスメソッドとインスタンスメソッドの 2 種類があり、static を付けるとクラスメソッドになります。クラスメソッドは クラス名 + "." + メソッド名 (引数, ...) で呼び出すことができます。new String[] {} は空の文字列の配列を生成します。配列は次回で詳しく説明します。

●文字

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

●文字列

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

jshell> String a = "abcd", b = "efgh", c = a + b
a ==> "abcd"
b ==> "efgh"
c ==> "abcdefgh"

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

演算子 + は文字列を連結するとき、左右どちらかのデータが文字列ではない場合、そのデータを文字列に変換してから連結します。

jshell> "1" + 2
$4 ==> "12"

jshell> 1 + "2"
$5 ==> "12"

たとえば、1 + 2 は整数の足し算で値は 3 になりますが、1 + "2" は 2 を文字列に変換して連結するので "12" になります。

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

●var

変数を "データ型 変数 = 初期値;" で定義する場合、左辺式のデータ型の部分を var に置き換えて記述することができます。

var 変数名 = 初期値;

Java は右辺式 (初期値) から変数のデータ型を推論します。これを「ローカル変数の型推論」といい、JDK 10 から導入された機能です。ローカル変数については次回以降で詳しく説明します。

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

jshell> var x = 123
x ==> 123

jshell> var y = 1.234
y ==> 1.234

jshell> var z = "foo bar baz"
z ==> "foo bar baz"

jshell> /vars
|    int x = 123
|    double y = 1.234
|    String z = "foo bar baz"

/vars は定義された変数を表示する JShell のコマンドです。変数 x のデータ型は int に、y は double に、z は String になります。なお、var x; のように右辺式を省略したり、var x = 123, y = 1.234; のように複数の変数を宣言することはできません。

●if 文

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


               図 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 文の入れ子

           図 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 文の構文

       図 7 : while 文の動作

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

簡単な例を示しましょう。Hello, World! を 10 回表示します。

jshell> int i = 0
i ==> 0

jshell> while (i < 10) { System.out.println("Hello, World!"); i += 1; }
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 回は必ず実行されます。簡単な例を示しましょう。

jshell> i = 0
i ==> 0

jshell> do { System.out.println("Hello, World!"); i += 1; } while (i < 10)
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!

これでも Hello, World! を 10 回表示することができます。

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

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

jshell> int i = 1, j = 10
i ==> 1
j ==> 10

jshell> int x = ++i
x ==> 2

jshell> int y = j++
y ==> 10

jshell> i
i ==> 2

jshell> j
j ==> 11

変数 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 までの総和を求めてみましょう。

jshell> int i = 1, sum = 0
i ==> 1
sum ==> 0

jshell> while (i <= 1000) sum += i++

jshell> sum
sum ==> 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 をお読みください。

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

リスト : 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++;
    }
  }
}
$ javac FizzBuzz.java
$ 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 をそのまま出力します。

●数値積分

最後に数値積分で円周率 \(\pi\) を求めてみましょう。区間 [a, b] の定積分 \(\int_a^b f(x) \, dx\) を数値的に求めるには、区間を細分して小区間の面積を求めて足し上げます。小区間の面積を求める一番簡単な方法は長方形で近似することです。この場合、3 つの方法が考えられます。

  1. (b - a) * f(a)
  2. (b - a) * f(b)
  3. (b - a) * f((a + b) / 2)

1 は左端の値 f(a) を、2 は右端の値 f(b) を、3 は中間点の値 f((a + b) / 2) を使って長方形の面積を計算します。この中で 3 番目の方法が一番精度が高く、これを「中点則」といいます。このほかに、台形で近似する「台形則」や、2 次近似で精度を上げる「シンプソン則」という方法があります。

それでは実際に、中点則で \(\pi\) の値を求めてみましょう。\(\pi\)は次の式で求めることができます。

\( \pi = \displaystyle \int_0^1 \dfrac{4}{1 + x^2} \, dx \)

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

リスト : 数値積分で円周率を求める (Midpoint.java)

public class Midpoint {
  public static void main(String[] args) {
    int n = 10000;
    double w = 1.0 / n;
    double s = 0.0;
    int i = 1;
    while (i <= n) {
      double x = (i - 0.5) * w;
      s += 4.0 / (1.0 + x * x);
      i++;
    }
    System.out.println(s * w);
  }
}

変数 n が分割数です。最初に小区間の幅を求めて変数 w にセットします。面積は変数 s にセットします。次の while ループで区間 [0, 1] を n 個に分割して面積を求めます。

最初に x 座標を計算します。中間点を求めるため、変数 i を 1 から始めて、x 座標を次の式で求めます。

x = (i - 0.5) * w

たとえば、変数 i が 1 の場合は 0.5 になるので、x は区間 [0 * w, 1 * w] の中間点になります。あとは、4 / (1 + x * x) を計算して s に加算します。最後に s に w を掛け算して全体の面積を求めます。

実行結果を示します。

$ javac Midpoint.java
$ java Midpoint
3.141592654423134

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

●問題

次のような九九表を表示するプログラム NinetyNine.java を作ってください。

   |  1  2  3  4  5  6  7  8  9
---+---------------------------
 1 |  1  2  3  4  5  6  7  8  9 
 2 |  2  4  6  8 10 12 14 16 18 
 3 |  3  6  9 12 15 18 21 24 27 
 4 |  4  8 12 16 20 24 28 32 36 
 5 |  5 10 15 20 25 30 35 40 45 
 6 |  6 12 18 24 30 36 42 48 54 
 7 |  7 14 21 28 35 42 49 56 63 
 8 |  8 16 24 32 40 48 56 64 72 
 9 |  9 18 27 36 45 54 63 72 81 












●解答

リスト : 九九表

public class NinetyNine {
  public static void main(String[] args) {
    System.out.println("   |  1  2  3  4  5  6  7  8  9");
    System.out.println("---+---------------------------");
    int i = 1;
    while (i <= 9) {
      int j = 1;
      System.out.print(" " + i + " | ");
      while (j <= 9) {
        int k = i * j;
        if (k < 10) {
          System.out.print(" " + k + " ");
        } else {
          System.out.print(k + " ");
        }
        j++;
      }
      System.out.println("");
      i++;
    }
  }
}
$ javac NinetyNine.java
$ java NinetyNine
   |  1  2  3  4  5  6  7  8  9
---+---------------------------
 1 |  1  2  3  4  5  6  7  8  9
 2 |  2  4  6  8 10 12 14 16 18
 3 |  3  6  9 12 15 18 21 24 27
 4 |  4  8 12 16 20 24 28 32 36
 5 |  5 10 15 20 25 30 35 40 45
 6 |  6 12 18 24 30 36 42 48 54
 7 |  7 14 21 28 35 42 49 56 63
 8 |  8 16 24 32 40 48 56 64 72
 9 |  9 18 27 36 45 54 63 72 81

九九表は二重の while ループで簡単に作ることができます。


初版 2009 年 4 月 4 日
改訂 2016 年 11 月 12 日
改訂二版 2021 年 2 月 7 日

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

[ PrevPage | Java | NextPage ]