2016年度 発展プログラミング演習 第1講 基礎の基礎

概要

目標

ここでは,次の内容を学びます.

この授業の進め方

この授業は,2つの教室に分かれてJava言語の基礎を学習します. この授業は演習ですので,履修上の注意 にも書かれている通り,一般の授業に比べて,欠席・遅刻・早退やレポートの未提出が成績に大きく影響します.

また,この講義では,大量のプログラムを書きます.それらのプログラムは捨ててはいけません. 後で説明しますが,ファイル名は自由につけられませんので, ディレクトリを掘ってそれぞれのプログラムを振り分けてください.

基本的に講義資料はすべてWebページとして公開します. 参考資料は,その都度紹介します.

この授業は市販の書籍とは異なり,intdoubleを使用しません. intdoubleを許してしまうと, 好む好まざるに関わらずC言語と似た書き方を続けてしまいます. そうすることでJavaらしい書き方に移行できなくなります. そのため,intdoubleは使用しません. その代わりにIntegerDoubleやその他の型を利用します. 型については,以降の単元でも説明していきます.

環境設定

エディタ

プログラムを書くためのエディタをインストールしておいてください. エディタは特に指定はありません. どのエディタが良いかわからない人は,とりあえず使ってみて, 使いやすいものを選んでください.

以下に候補を挙げます(ここに挙がっていないからといって,使ってはダメということはありません). ここに挙げているエディタは全て無料です.

GNU Emacs for Mac OS X
基礎プログラミング演習Iでも使っていたエディタ.高機能かつ,癖がある.しかし,慣れるとマウスを使わず作業ができる.
VIM
Emacsと同じく,高機能かつ,癖のあるエディタ.愛好家も多い.
Atom
Web技術を主な対象とするエディタ.
CotEditor
日本で生まれたシンプルなエディタ.必要最小限のものが揃っている.
mi
OX X専用のエディタ.古くからある.
Sublime Text
高機能なエディタ.特徴を一言でまとめるのは難しいので,紹介記事を参照のこと.
Brackets
アドビが開発するエディタ.主要なターゲットとする言語は,HTML, CSS, JavaScript.

その他

ここでは,その他のアプリケーションを紹介します. インストールされていなくても困ることはありませんが, インストールされているとちょっと便利なアプリケーションです.

Dash
APIリファレンスをオフラインで高速に検索できるMac用アプリケーション.
Kobito
Markdownエディタ.プログラミングのメモや,コード断片の記録に.Qiitaが提供するアプリケーションであるため,Qiitaへの投稿もできる.

Java環境

ターミナルでインストールされているJava環境を確認しましょう.

$ java -version
java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

一行目が出力,2行目以降がコマンドの出力結果を示しています. 2行目を確認してみましょう.ここが,1.8.0_xx (xxはどのような数字でも構いませんが大きな値の方が良いです)であれば, Java SE 8 がインストールされています.

Java SE 8とは,Java の Standard Edition のバージョン8ということを表しています. Standard Edition 以外に,Webアプリケーションを対象としたEnterprise Editionや モバイルアプリを対象とした Micro Editionが存在します. そして,バージョン8と書きましたが,コマンドの実行結果は,1.8.0_73 と表示されています. これは,バージョン8と1.8.0の2つの書き方があるのは歴史的経緯です. また,後ろの 73 はバージョン8の中で73回のアップデートが行われたことを表しています.

この部分が,1.7.0_xx1.6.0_xxとなっている場合は 古いJavaのバージョンがインストールされており,最新版がインストールされていません. また,command not foundと出力された場合は,Java自体がインストールされていません. このような場合,最新のJavaをインストールする必要があります.

1.7.0_xx1.6.0_xxは既にサポートが終了しており, セキュリティホールなどに対応されません.そのため,本演習に於いても, これら古いバージョンのJavaの仕様は推奨せず,最新の1.8.0_xx を利用することを推奨しています.

具体的な Java の最新バージョンのインストール方法は,Javaのインストール方法を参照してください.

ターミナルの基本的な使い方

ファイルやディレクトリの指定

絶対パス
/Users/kyosantaro/Java/basic/HelloWorld.java
カレントディレクトリからの相対パス
basic/HelloWorld.java
カレントディレクトリからの相対パス2
HelloWorld.java
カレントディレクトリからの相対パス3 (. はカレントディレクトリを表す)
./HelloWorld.java
カレントディレクトリからの相対パス3 (.. は親ディレクトリを表す)
../basic/HelloWorld.java
ホームディレクトリからの相対パス (~ はホームディレクトリを表す)
~/Java/basic/HelloWorld.java

基本的なコマンド

cat [files...]
ファイルの内容を出力する.
less <files...>
ファイルの内容を1ページずつ表示する.
mv <from...> <to>
ファイルやディレクトリを<from...>から<to>へ移動する(<to>が存在し,ディレクトリの場合)
ファイルやディレクトリの名前を<from>から<to>へ変更する(<to>が存在しない,もしくは,ファイルの場合).
cp <from> <to>
指定されたファイルをコピーする.<from>から<to>へコピーする.
rm <files...>
指定されたファイルを削除する.
mkdir <dir>
指定されたディレクトリを作成する.
rmdir <dir>
指定されたディレクトリを削除する.ただし,<dir>内にファイルやディレクトリが残っていれば失敗する.
pwd
カレントディレクトリを絶対パスで表示する.
ls [dir]
指定されたディレクトリ内にあるファイルやディレクトリの一覧を表示する.ディレクトリが指定されなかった場合は,カレントディレクトリの内容を表示する.
cd [dir]
指定されたディレクトリに移動する.ディレクトリが指定されなかった場合は,ホームディレクトリに移動する.
find <dir>
指定されたディレクトリ(<dir>)以下の特定のファイルを探す.ファイルの特定は様々なオプションで指定する.
which <program>
指定されたプログラム(<program>)が存在する場所を探す.

リダイレクト,パイプ

プログラム(prog)の出力結果をファイル(file)に書き出す(両方共結果は同じ).
$ prog 1> file
$ prog > file
プログラム(prog)の出力結果をファイル(file)に追記する.
$ prog >> file
ファイル(file)の内容をプログラム(prog)の標準入力に流す.
$ prog < file
プログラム(prog)の標準エラー出力を標準出力に出力する.
$ prog 2>&1 
プログラム(prog)の標準エラー出力を捨て,標準出力をファイル(file)に出力する(両方共結果は同じ).
$ prog 2> /dev/null 1> file
$ prog 2> /dev/null > file 

/dev/nullは特別なファイルである.ここに書き込まれた内容は破棄され,ここから読み出すと空ファイルとなる.

出力まとめ
$ プログラム fd> 出力先

fdはファイルディスクリプタを示す数値.標準入力(stdin)は0, 標準出力(stdout)は1,標準エラー出力(stderr)は2.fdが1の場合は省略可能.

プログラム1(prog1)の出力結果をプログラム2(prog2)の入力に渡す.
$ prog1 | prog2
findの結果を1ページずつ表示する.
$ find hoge -name '*.java' | less

Javaプログラムの作成から実行まで

ソースファイル作成

ソースファイルの名前は,ソースファイルの内容に従って決まります. 好き勝手に名前が付けられるわけではないことに注意してください. 拡張子は,.javaです.

例えば,次のような内容のソースファイルの場合,名前は HelloWorld.javaとなります. ソースファイル中のclassの後ろに付けられた名前(以下の例の場合, HelloWorld)に拡張子を付けた名前がファイルの名前になります. 大文字小文字を区別するので,注意してください.

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

コンパイル

Java言語でも,コンパイルが必要です.コンパイルはjavacコマンドで実行します. 先ほど作成した HelloWorld.javaをコンパイルしてみましょう.

$ javac HelloWorld.java

コンパイル前後のファイル

javacコマンドを使ってJavaのソースファイルをコン パイルすると,上の図のように,クラスファイルが作成されます. この場合も,大文字小文字を区別しますので注意してください.コ ンパイルに成功すると,ターミナルには何も出力されず, HelloWorld.classが作成されます.lsコマンドで確認してみましょう.

コンパイルエラー

コンパイルに失敗すると,どこに間違いがあるかをコンパイラが示してくれます. 例えば,上記ソースファイルの3行目の最後に,セミコロンを入力し忘れた場合を考えてみます. セミコロンを入力しなかったソースファイルをコンパイルすると,コンパイラは次のようなエラーを出力します.

HelloWorld.java:3: エラー: ';'がありません
        System.out.println("Hello World")
                                         ^
エラー1個

このとき,1行目にファイル名:行番号:エラー種別が示されています. つまり,HelloWorld.javaの3行目にセミコロンがない,というエラーであることがわかります. そして,2行目以降に当該行の具体的なエラー箇所が示されています. このように,具体的にどの部分かということを示してくれていますので, しっかりとエラーメッセージを読むようにしましょう.

代表的なコンパイルエラーを次に列挙します.コンパイルエラー程度は,自力で修正できるようにしましょう.

シンボルが見つかりません.
宣言されていない変数を使おうとしたときに指摘されます.変数は参照できる場所に宣言されていますか,綴りは間違っていませんか.
クラスXxxxはpublicであり,ファイルXxxx.javaで宣言しなければなりません
Javaではクラス名とファイル名は必ず一致させておかなければいけません.クラス名とファイル名が一致しているか確認しましょう.
<identifier>がありません.
publicやstatic,classなどの間違いが疑われます. public static void main(String[] args)は間違いなく書かれていますか. 一番外側に,public class Xxxxのように囲んでいますか.
\12288は不正な文字です.
全角スペースが入っていないか確認してください.全角スペースはC言語と同じく許されていません.

実行

Javaプログラム(.javaファイル)はコンパイルするとクラスファイル (.class)に変換されます.変換後のクラスファイルを実行するのですが, C言語のa.outを実行したときのように,以下のような実行はできません.

$ ./HelloWorld.class

Javaプログラムは必ず,JVM (Java Virtual Machine; Java仮想マシン)の上で実行されます. そのため,JVMを起動する必要があります.JVMを起動するコマンドが java コマンドです. 次のように,コマンドを実行してみましょう.

$ java HelloWorld
Hello World

しっかりと,"Hello World"と出力されましたか? javaコマンドでクラスファイルを実行するときには,拡張子 (.class)を付けません.

プログラムを読む

実行できたところで,作成したプログラムを確認してみましょう.

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

一番外側

Javaプログラムは必ず一番外側が public class Xxxx で囲まれている必要があります.この一番外側の囲みを クラス宣言と呼びます. 変数も関数も必ずこのクラス宣言に囲まれた部分でしか定義できません.

クラス宣言の外側に書ける内容は,パッケージ宣言,import 文のみです. パッケージ宣言は,この講義の範囲から外れるため,説明は省略します. import文は標準ライブラリの中から利用するライブラリを指定することで, プログラム中では省略して記載できるようになる機能です.

例えば,Systemは標準ライブラリに含まれる部品の一つです. 本来であれば,java.lang.Systemと記載しなければいけません. このときのjava.langをパッケージ名,Systemをクラス名と呼び, java.lang.Systemというように,パッケージ名を含めて表記することを, 完全修飾名と呼びます. 基本的に,Javaプログラムは,全ての部品は完全修飾名で記載する必要があるのですが, import 文を書くことで,クラス名のみの記載に省略できるようになっています.

ただし,java.langパッケージに属する部品は暗黙的に import 文が書かれているため,Systemjava.lang.System と記載せず,Systemという省略形で書けるようになっています. 基本的には,この授業で扱うクラスでimport文が必要なクラスは, 初出の時にどのようなimport文が必要であるかを明記します.

関数ならぬメソッド

Javaでは,ひとまとまりにした命令の集合(C言語で言うところの関数)のことを, メソッドと呼びます. 上でも述べたように,メソッドは必ず一番外側のクラス宣言の 波括弧(curly brace) で囲まれた部分で宣言されます.

上記のメソッドは,返り値がvoid,つまり何も返さないメソッドであり, 引数として,String型の配列を受け取るということがわかります. では,publicstatic とは何でしょうか. publicは,可視性と呼ばれるものです. 可視性は,この演習の最後の方で扱いますので,今はpublicのみを知っておけば良いです. また,staticも,main メソッドに特別に付けるキーワードとして覚えてください.

プログラムの起動

Javaプログラムが起動するとmainメソッドが呼び出されます. mainメソッドは,必ず public static void main(String[] args) でなければいけません(このうち,argsは変数名であるため,変更可能ですが). javaコマンドでクラスを指定すると,そのクラス内で定義されている mainメソッドが検索されます.見つかればそのメソッドが実行されることで, Javaプログラムが実行されます.

標準出力への出力

mainメソッドの中で何を行っているのかを確認しましょう. mainの中は一行のみです.

System.out.println("Hello World");

実行するとわかると思いますが,この一行は,標準出力Hello Worldという文字列を改行付きで出力します. C言語でのputsに相当します. もし,改行を付けずに出力したい場合は,System.out.printを使いましょう.

System.out.printlnも,System.out.printも, printfのようなフォーマット付き出力には対応していません. しかし,Javaにも,フォーマット付き出力を行うためのメソッドである System.out.printfが存在します.フォーマット付きの出力を行いたい場合は, System.out.printfを利用しましょう.出力形式を次にまとめます.

System.out.print
引数に与えられたデータを改行なしで出力する.引数に与える型は何でも良い.
System.out.println
引数に与えられたデータを改行付きで出力する.引数に与える型は何でも良い.
System.out.printf
引数に与えられたデータをフォーマットに従って出力する. 第1引数に出力するフォーマット形式,第2引数以降に,出力する値が渡される. C言語のprintfとほぼ同じ.改行方法のみが異なる. C言語では改行するのに,\nを使いましたが,Javaでは, %nを使います.詳細は,FAQC言語のprintfのようなフォーマット付きの出力は使えますか? を参照してください.

練習問題

1. ディレクトリ作成

この授業で作成するJavaプログラム用に,ホームディレクトリ以下にディレクトリを作成しましょう. ディレクトリの名前は,cseapとします.

作成できれば,cseapディレクトリに移動し,次の5つのディレクトリを作成しましょう.

これらのディレクトリが今後,この授業で作成するソースファイルを格納するディレクトリとなります. これらのディレクトリ一覧を cseap/list.txt に出力してください(list.txtの内容にlist.txtが含まれていても構いません).

なお,これから,$CSEAPと表記した場合は, ~/cseapを指すものとします.

これ以降の練習問題は,$CSEAP/basic/practice というディレクトリを作成し,そこに格納しましょう.

2. 加算器 (Adder).

次のプログラムを作成しましょう.

  1. クラス名は,Adder とする.
  2. mainメソッドを用意する.
  3. mainメソッド内でInteger型の変数 resultを宣言する.
  4. 1+2resultに代入する.
  5. resultSystem.out.printlnを使って出力する.

変数の宣言は,C言語と同じように,型 変数名;の順に書きます. 変数への値代入もC言語と同じように=を利用します. また,Javaでも,変数は利用する前に宣言しなければいけません.

完成すれば,1, 2の値を自由に変更して実行結果を確認してみましょう.

3. Big&Small

0から9までの乱数を発生させ,その値が4以下であれば,Small,4より大きければBig と出力するプログラムを作成する.0から9までの乱数は,次のコードで得られます.

Random rand = new Random();
Integer value = rand.nextInt(10);

なお,このコードを利用する場合は,プログラムの一番最初の行に,import java.util.*; の記述が必要です. では,次の指示に従って作成していきましょう.

  1. クラス名をBigAndSmallとします.
  2. ソースファイルの先頭(クラスの宣言よりも前)にimport java.util.*;を書いてください. なお,この文は java.utilパッケージに所属する すべてのクラスをインポートすることを意味します.詳細は後日説明します.
  3. mainメソッドを用意してください.
  4. mainメソッド内で,Random型の変数 randを用意し,上記のプログラムの断片を参考に値を代入します. つまり,Random rand = new Random();の一行を追加することを意味します.
  5. mainメソッド内でInteger型の変数valueを宣言してください.
  6. 変数valueに乱数値を代入します.rand.nextInt(10); の呼び出しにより,0から9の乱数が得られます.
  7. 変数valueの値をSystem.out.printlnを用いて出力しましょう.
  8. 変数valueの値を調べ,SmallもしくはBigをSystem.out.println を用いて出力しましょう.

条件分岐はC言語と同じように書けます.if文を利用し, Integer型の変数valueの値を調べましょう. 完成すれば,何度か実行し,値が毎回変わっているか,期待通りに判定できているか,を確認しましょう.

4. 総和を求める

ループを用いて,1から10までの総和(10を含む)を求めましょう.次の手順で作成していきましょう.

  1. クラス名をGrandTotal とする.
  2. mainメソッドを用意する.
  3. mainメソッド内でInteger型の変数 resultを宣言する.resultは初期値として0を代入しておく.
  4. mainメソッド内でInteger型のループ制御変数iを宣言する.
  5. ループ制御変数iを用いて1から10までループを作成する.
  6. 繰り返しごとに,resultiの値を加算していく.
  7. ループ終了後,resultの値を出力する.

ループはC言語と同じように書けます. forwhileのどちらも利用できますので,試してみましょう.

完成すれば,範囲を変更して,総和を求めましょう.

5. Xの描画

繰り返しを用いて,次の出力になるようにプログラムを書きましょう.

   0123456789
0: X        X
1:  X      X
2:   X    X
3:    X  X
4:     XX
5:     XX
6:    X  X
7:   X    X
8:  X      X
9: X        X
System.out.println(i + ": ");

なお,0:は,左のように書くことで出力できます. これは,変数iと文字列": "を繋げて出力しています. このように,+で文字列を自由に繋げられます. この時,型は自動的にString型に変換されます.

どこから手をつけて良いかわからない人は,まず, 左上から右下にXを書くプログラムを2重ループを用いて書いてみましょう. 次のような出力になるはずです.

   0123456789
0: X
1:  X
2:   X
3:    X
4:     X
5:      X
6:       X
7:        X
8:         X
9:          X

次に,右上から左下にXを書くプログラムを先ほどのプログラムと同じように,2重ループで書きましょう. 次のような出力になるようにプログラムを書いてください.

   0123456789
0:          X
1:         X
2:        X
3:       X
4:      X
5:     X
6:    X
7:   X
8:  X
9: X

その後,2つのプログラムをどうやって組み合わせるかを考えましょう.

  1. クラス名をDrawXとします.
  2. mainメソッドを用意してください.
  3. 行を書くための繰り返しを書きます.
    1. 0行目では,0列目と9列目(9-0)にXを書きます.
    2. 1行目では,1列目と8列目(9-1)にXを書きます.
    3. 2行目では,2列目と7列目(9-2)にXを書きます.
    4. ...
    5. 上記を繰り返しでどのように書くかを考えましょう.

単に改行したい場合は,System.out.println();と言う呼び出しを行ってください.

まとめ

本日,学んだ内容は次の通りです.