[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

情報処理技法(Javaプログラミング)I 第3回

目次
索引

操作法のヒント

よく利用するアプリケーションは、Dockに登録しておくと、次回からはワンクリックで起動できるようになります。 登録したいアプリケーションは、起動したときにDockに現れるアイコンを右クリックし、「オプション」→「Dockに追加」とクリックしてください。

Jeditで、プログラムを修正するとき、何行目かが分かると便利です。 そのときは、メニューバーで「表示」→「行番号を表示」→「狭い幅で」とクリックして、行番号を表示してください。

「ターミナル」でコマンドを入力するとき、以下のキーを押すと、入力が楽になります。

tabキー
自動的に残りの部分が入力されます。 ただし、残りの部分に複数の候補がある場合は、自動入力されるのはその共通部分のみです。
上矢印キー
直前に入力したコマンドが現れます。 何度も押すと、その前、その前と表示されます。
下矢印キー
直後に入力したコマンドが現れます。 何度も押すと、その後、その後と表示されます。

アルゴリズムとプログラム

アルゴリズムとは

前々回の授業では、プログラムとは何かについて説明しました。 人間がプログラムを作ってパソコンに与えると、パソコンはそのプログラムに従って動くという内容です。 プログラムには、もう一つの特徴付けがあります。 それは、「プログラムとはアルゴリズムの具体的な表現である。」です。 ここで、 アルゴリズム ( algorithm )とは、問題を解決するための手順のことです。

アルゴリズムの説明で、問題解決と言われても、ピンと来ないかもしれません。 例として、次の問題を考えます。

与えられた文字列が回文か否かを判定せよ。 ここで回文とは、「たけやぶやけた」のように、左から読んでも右から読んでも同じになる文字列のことである。

この問題は、次のような手順で解決できます。

  1. 与えられた文字列を s1 とする。
  2. s1 の左右を逆転した文字列を生成し、その文字列を s2 とする。
  3. s1 と s2 を左から一文字ずつ比較する。
  4. もし途中で文字の違いが見つかったら"No"と答える。
  5. 最後まで文字の違いが見つからなかったら"Yes"と答える。

今、「いるかはまるい」という文字列が与えられたとします。 s1 は「いるかはまるい」に、 s2 は「いるまはかるい」になります。 左から一文字ずつ比較すると、3文字目で違いが見つかるので、"No"と答えます。 一方、「たけやぶやけた」の場合は、 s1 は「たけやぶやけた」に、 s2 も「たけやぶやけた」になります。 左から一文字ずつ比較しても違いは見つからないので、"Yes"と答えるというわけです。

この手順は、回文判定のアルゴリズムと言えます。 実際、この手順によって、回文を判定するという問題が解決します。

アルゴリズムは必ずしも一つとは限りません。 以下も回文判定のアルゴリズムです。

  1. 与えられた文字列を s1 とする。
  2. s1 の左から1番目の文字と右から1番目の文字、左から2番目の文字と右から2番目の文字、…と順番に比較する。
  3. もし途中で文字の違いが見つかったら"No"と答える。
  4. 文字列の中央になるまで違いが見つからなかったら"Yes"と答える。

アルゴリズムとプログラミング言語

アルゴリズムが分かっても、そのままではパソコンは問題解決をしてくれません。 パソコンが日本語を理解するわけでもないですし、どうやって「左右を逆転した文字列を生成」するのかも、はっきりしていません。 パソコンに問題解決をしてもらうには、パソコンに処理できるような形で、アルゴリズムを具体的に表現する必要があります。 この表現のための言語がプログラミング言語であり、表現自身がプログラムです。

Javaはプログラミング言語の一つです。 この授業の目的は、アルゴリズムをJavaのプログラムで表現し、パソコンに問題解決をさせることであると言えます。 Javaを覚えることと、アルゴリズムを見つけることは、無関係ではありません。 Javaの知識があればこそ、Javaで表現しやすいアルゴリズムが構成できるからです。 授業では、Java、アルゴリズム、およびプログラミングを並行して身につけることにします。

なお、プログラミング言語はJavaの他にもたくさんあります。 現在よく使われているのは、C, C++, Javaです。 それなりに使われているのは、Fortran, Cobol, Lisp, Basic, Pascal, Prologといったところです。 プログラミング言語が変われば、解決しやすい問題の種類や、プログラムに対する考え方が変わります。 今はJavaで精一杯かもしれませんが、色々なプログラミング言語を経験し、問題や考え方に応じてプログラミング言語を選べるようになるのが理想的です。


コメントとインデント

コメント

プログラムの一部や全部の説明文がプログラムの中に書けると、プログラマにとってプログラムが理解しやすくなります。 このような説明文を コメント ( comment )とよびます。 javacコマンド(Javaコンパイラ)は、プログラムに記号 // が現れると、そこから行末までを無視します。 そこにコメントを書けば、プログラムに影響を与えずにプログラムの説明ができます。 次のプログラムはコメントの使用例です。

// k12x1001 東 京子 2015年10月9日
class ProgramTest {
    public static void main (String[] args) {
        System.out.println("OK"); // 動作確認
    }
}

また、記号 /* と */ に囲まれた部分も無視されます。 このふたつは同じ行にある必要はないので、たくさんの行を一度にコメント指定できます。 ただし、このコメントは入れ子にできません。 例えば、

System.out.println("OK");
/*
    System.out.println("Good");
    System.out.println("Nice");
*/
System.out.println("Excellent");

という部分をコメント指定しようとして、

/*
    System.out.println("OK");
    /*
        System.out.println("Good");
        System.out.println("Nice");
    */
    System.out.println("Excellent");
*/

と書いても、最初の */ までがコメントだと見なされてしまいます。

インデント

プログラムの行頭のスペース(字下げ)は インデント ( indent )とよばれます。 javacコマンド(Javaコンパイラ)は行頭のスペースを無視します。 インデントをうまく使うと、プログラムの構造を見やすくできます。

上記のプログラムでインデントを用いないと

// k12x1001 東 京子 2014年10月9日
class ProgramTest {
public static void main (String[] args) {
System.out.println("OK"); // 動作確認
}
}

となります。 最後の2つの閉じブレース( } )がそれぞれどの開きブレース( { )に対応しているかが分かりにくいです。 インデントを用いずに長いプログラムを書くと、ブレースの対応が分からなくなり、プログラムの構造を見えなくしてしまいます。

この授業では、次の規則でインデントをします。


式と演算子(1)

前々回の授業では、Javaアプリケーションの例として、「ターミナル」にOKと出力するプログラムを動かしてみました。 また、前回は、アプレットの例として、絵を描くプログラムを作成しました。 今回は、再びアプリケーションに戻って、数(特に整数)を取り扱うことにします。

次のプログラムを動かすと、「ターミナル」で以下のような出力が得られます。

/*  1*/ class ExpressionTest { // 式のテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println(100);
/*  4*/         System.out.println(250 + 100);
/*  5*/         System.out.println(250 - 100);
/*  6*/         System.out.println(250 * 100); // 掛け算
/*  7*/         System.out.println(250 / 100); // 割り算
/*  8*/         System.out.println(250 % 100); // 割った余り
/*  9*/         System.out.println(1000 + 250 * 3);
/* 10*/     }
/* 11*/ }
24102a1:java1 k12x1001$ javac ExpressionTest.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java ExpressionTest
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
100
350
150
25000
2
50
1750
24102a1:java1 k12x1001$

プログラムの最初の2行はそのまま書くものと考えてください。 ただし、 class の右はファイル名です。

プログラム中の 250 + 100 , 250 - 100 などは 式 ( expression )とよばれるものです。 プログラムを動かすと、式が計算されているのが分かります。 ここで、記号 * が掛け算を表していることに注意してください。 また、記号 / は割り算を表していますが、この場合は2余り50という計算をして、2を計算結果としています。 余りを求めるには、 / の代わりに % を書きます。

+ , - , * , / , % などを 演算子 ( operator )とよびます。

整数(int型)の演算子
記号 演算 例
+ 足し算 19 + 3 ⇒ 22
- 引き算 19 - 3 ⇒ 16
* 掛け算 19 * 3 ⇒ 57
/ 割り算 19 / 3 ⇒ 6
% 割った余り 19 % 3 ⇒ 1

上記の最後の出力を見ると、式 1000 + 250 * 3 の計算は、はじめに掛け算をして、次に足し算をしていることが分かります。 これは、演算子 + より * のほうが優先順位が高いと決められていて、式は優先順位の高い演算子から順に計算されるからです。 もし、足し算を先に計算したければ、括弧を使って (1000 + 250) * 3 と書いてください。 この式の計算結果は3750となります。

演算子の優先順位について簡単に説明します。 まず、括弧の中が最優先で計算されます。 次に演算子 * , / , および % が優先します。 最も優先順位が低いのは演算子 + と - です。 ここで注意すべきことは、 + と - は同じ優先順位であり、これらが続いているときは左から右に計算されることです。 例えば、式 5 - 3 + 1 は (5 - 3) + 1 と見なされ、3という計算結果になります。 演算子 * , / , % についても同様です。

注意: 割り算で、0 で割ることはできません。 もし、そのような計算を行うと、エラーが発生してプログラムは途中で停止します。 javacコマンドが成功しても、プログラムが動くとは限らないのです。

/*  1*/ class DivisionTest { // 割り算のテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println(100 / 2);
/*  4*/         System.out.println(100 / 0); // エラー
/*  5*/         System.out.println(100 / 5);
/*  6*/     }
/*  7*/ }
24102a1:java1 k12x1001$ javac DivisionTest.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java DivisionTest
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
50
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at DivisionTest.main(DivisionTest.java:4)
24102a1:java1 k12x1001$

変数と代入文(1)

変数とは

プログラムでは、 変数 ( variable )というものが重要な役割を果たします。 変数とは、数などのデータが格納できる「入れ物」であると考えてください。 次の図は変数のイメージです。

変数のイメージ
変数のイメージ

変数には名前が付いています。 これを 変数名 ( variable name )とよびます。 この場合は x です。 また、変数にはデータがひとつ格納できます。 これを変数の 値 ( value )とよびます。 この場合、変数 x の値は100です。

変数を使えるようにするには、変数の 宣言 ( declaration )という手続きが必要です。 変数の宣言を行うのが 宣言文 ( declaration statement )です。

変数にデータを格納することを、 代入 ( assignment )と言います。 代入を行うのが 代入文 ( assignment statement )です。

変数に格納されたデータを取り出すには、式の中で数の代わりに変数名を書きます。

以下は変数を使ったプログラムの例です。

/*  1*/ class VariableTest { // 変数のテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         int x; // 宣言文
/*  4*/         x = 100; // 代入文
/*  5*/         System.out.println(x);
/*  6*/     }
/*  7*/ }
24102a1:java1 k12x1001$ javac VariableTest.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java VariableTest
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
100
24102a1:java1 k12x1001$

3行目では、変数の宣言を行って、変数を使えるようにしています。 変数名を x とし、ここに格納するデータの種類(型といいます)は整数(int型)だと言っています。

宣言文は、整数の場合は

int 変数;

という形が基本です。

4行目は代入文です。 変数 x にデータ100を格納します。

代入文は、一般的に

変数 = 式;

という形をとります。 「 変数 」に「 式 」の計算結果を格納するということです。 単なる数や変数も式の一種です。 従って、

変数 = 数;

ならば、「 変数 」に「 数 」を格納しますし、

変数1 = 変数2;

ならば、「 変数1 」に「 変数2 」の値を格納します。

5行目は結果の出力です。 変数 x にはデータ100が格納されているので、

System.out.println(x);

の部分が

System.out.println(100);

と書いたように振舞います。

なお、変数名はプログラマが決めます。 英単語などを使って、分かりやすい変数名にしてください。 数学の変数のように、1文字にする必要はありません。 変数名の条件は、アルファベットの大文字か小文字で始まり、アルファベットの大文字、小文字、数字、アンダースコア(_)を並べた文字列です。 ただし、次の文字列はJavaで特別な意味を持つ キーワード なので、変数名としては使えません。

Javaのキーワード
A abstract assert
B boolean break byte
C case catch char class const continue
D default do double
E else enum extends
F final finally float for
G goto
I if implements import instanceof int interface
L long
N native new
P package private protected public
R return
S short static strictfp super switch synchronized
T this throw throws transient try
V void volatile
W while

また、 null , true , false も変数名としては使えません。

Javaらしい変数名の付け方は、英単語を続けて書き、2番目以降の単語の先頭を大文字にするというものです。 例えば、ペットボトルの値段を表す変数名としては、次のようなものが考えられます。

pet , petBottle
値段を表しているのが明らかなとき。
price , unitPrice
ペットボトルを表しているのが明らかなとき。
petPrice , petBottlePrice
何を表しているかが明らかでないとき。
pet1 , pet2
数種類のペットボトルがあるとき。

次のプログラムはいくつかの変数を使う例です。

/*  1*/ class SomeVariables { // いくつかの変数
/*  2*/     public static void main (String[] args) {
/*  3*/         int temp1, temp2, temp3;
/*  4*/         temp1 = 300;
/*  5*/         temp2 = 200;
/*  6*/         temp3 = 4 * temp1 + 3 * temp2;
/*  7*/         System.out.println(temp3);
/*  8*/         System.out.println(4 * 300 + 3 * 200);
/*  9*/     }
/* 10*/ }
24102a1:java1 k12x1001$ javac SomeVariables.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java SomeVariables
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
1800
1800
24102a1:java1 k12x1001$

3行目で、3つの変数 temp1 , temp2 , temp3 を宣言します(temporary=一時的な)。 これは、変数の宣言

int temp1;
int temp2;
int temp3;

をまとめたものです。 6行目で、変数 temp3 に式 4× temp1 +3× temp2 の値を代入します。 変数 temp1 の値は300で、 temp2 の値は200なので、4×300+3×200を計算して、この値1800が変数 temp3 に格納されます。

変数の初期化

前小節では次のようなプログラムを動かしました。

/*  1*/ class VariableTest {
/*  2*/     public static void main (String[] args) {
/*  3*/         int x;
/*  4*/         x = 100;
/*  5*/         System.out.println(x);
/*  6*/     }
/*  7*/ }

変数の宣言とデータの格納は一緒に行うことができます。 この操作を変数の 初期化 ( initialization )とよび、そのデータをその変数の 初期値 ( initial value )とよびます。 次のプログラムの3行目で、変数 x を100に初期化しています。

/*  1*/ class VariableTest2 { // 変数のテスト2
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100; // 初期化
/*  4*/         System.out.println(x);
/*  5*/     }
/*  6*/ }

次のように書くと、複数の変数が初期化できます。

int x = 100, y = 200;

次のように、変数の初期化と単なる宣言を混ぜることもできます。

int x = 100, y = 200, z;

変数の値の変更

今までの例では、変数に格納されたデータは特に変更されませんでした。 一般的には、変数に格納されたデータは何度も変更されます。

/*  1*/ class VariableTest3 { // 変数のテスト3
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100;
/*  4*/         x = 101; // 101を格納
/*  5*/         System.out.println(x);
/*  6*/     }
/*  7*/ }
24102a1:java1 k12x1001$ javac VariableTest3.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java VariableTest3
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
101
24102a1:java1 k12x1001$

このプログラムは、変数 x にデータ100を格納した後、さらにデータ101を格納するものです。 5行目で変数 x の値を取り出すと、101になります。 最初のデータ100は上書きされてしまいます。 このイメージは次の図のようになります。

変数の値の変更
変数の値の変更

変数の使用例

変数の使用例として、次の問題を考えます。

A子は店に行き、150円のペットボトルを1本と120円の缶ジュースを3本買いました。 A子はいくら支払わなければならないでしょうか。

この問題を解決するには、式 150+3×120 を計算するのが簡単です。 プログラムは次の通りです。

/*  1*/ class SomeDrinks { // いくつかの飲み物
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println(150 + 3 * 120);
/*  4*/     }
/*  5*/ }
24102a1:java1 k12x1001$ javac SomeDrinks.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java SomeDrinks
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
510
24102a1:java1 k12x1001$

変数に計算結果を格納するアルゴリズムもあります。 まず、合計金額を表す変数 total を宣言しておきます。 次に、式を計算し、その結果を変数 total に格納します。 最後に、変数 total の値を取り出して出力します。

合計金額だけではなく、ペットボトルと缶ジュースの値段も変数に格納しておくと、より分かりやすくなります。 変数名は、それぞれ pet , can とします。 プログラムは次の通りです。

/*  1*/ class SomeDrinks2 { // いくつかの飲み物2
/*  2*/     public static void main (String[] args) {
/*  3*/         int total, pet = 150, can = 120;
/*  4*/         total = pet + 3 * can;
/*  5*/         System.out.println(total);
/*  6*/     }
/*  7*/ }

演習3

次の問題を考えます。

B子はドラッグストアに行き、100円のティッシュを5箱と200円の石けんを2個と300円のタオルを1枚買いました。 B子はいくら支払わなければならないでしょうか。

この問題を解決するアルゴリズムを考え、プログラムを作成してください。 プログラムでは、変数を適切に利用してください。

24102a1:java1 k12x1001$ javac Drugstore.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
24102a1:java1 k12x1001$ java Drugstore
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
1200
24102a1:java1 k12x1001$

余力のある人は、同じような買い物を自分で考え、支払金額を求めるプログラムを作成してください。 プログラムは、何を買ったかが分かるようにしてください。


レポート課題

今日の演習3の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(学生番号@cis.twcu.ac.jp)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(10月9日)を明記してください。


参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2015年10月9日更新
小西 善二郎 <konishi@cis.twcu.ac.jp>
Copyright (C) 2015 Zenjiro Konishi. All rights reserved.