情報処理技法(Javaプログラミング)I
Table of Contents
- 1. Java言語の学習方法 #01
- 2. 字句構造:プログラミングの基礎知識 #02
- 3. 字句構造:プログラミングの表記法 #03
- 4. 字句構造:型と様々な直値 #04
- 5. 変数の宣言・代入・参照・初期化と名前 #05
- 6. 式の評価と数値の演算 #06
- 7. 論理演算・比較演算 #07
- 8. 型変換 #08
- 9. 文字列型(String) #09
- 10. 文字列の比較や長さ #10
- 11. 配列型(Array) #11
- 12. 構造化プログラミング1
- 13. 構造化プログラミング2 #12
- 14. 構造化プログラミング3 #13
- 15. 最終課題
ar#+STARTUP: overview indent num align inlineimages logdone hidestars hideblocks
1. Java言語の学習方法 #01
1.1. はじめに
- この授業では、プログラミングの楽しさ、奥深さ、魅力を学ぶ
- 他のプログラミングにも役立つ、「プログラミングの本質」に迫る
- レベルは初心者に合わせる
- 後期のJava2授業と合わせて履修するのが望ましい
1.2. どうしてJava言語を学ぶのか
- プログラミングを学ぶと何ができるようになるか?
- アプリが作れるようになる!
- Java言語で作られたアプリ
- みなさんがITを学ぶ価値
- ワークライフバランス
- ライフステージ
- プログラミング教育必修化のすべてがわかる!まるわかりガイド | コエテコ
1.3. Javaの開発環境(repl.it)
- Java言語でプログラミングを書く基本的な環境
- Java Downloads | Oracle
- ソースコードを書くためのテキストエディタ
- 統合開発環境(IDE)
- クラウド型環境
- Replit(れぷるいと)とは?
- repl.itとはWebブラウザのみで完結するプログラミング環境
- 多くのプログラミング言語で利用可能(この授業ではJava)
- Replitを使って演習や課題を行う → 使えるようになろう!
1.4. Javaの公式ドキュメント
- Javaの開発を行っている会社
- 最新のJavaのバージョン
- Java SE 18 Edition
- Java開発環境に関する文書
- Java言語の仕様書
1.5. Java言語のソースコード
簡単なJava言語のコードを見てみよう。
1: class Main { 2: public static void main(String[] args) { 3: System.out.println("Hello World"); 4: } 5: }
これは 標準出力 に「Hello World」という 文字列 を出力(表示)するプログラムである。
なお、行頭の番号(「1:」等)は行番号であり、実際のプログラムには書かない。
ちなみに、同じプログラムをC言語で書くと、
1: #include <stdio.h> 2: void main() { 3: printf("Hello World\n"); 4: }
ちなみに、同じプログラムをPythonで書くと、
1: print('Hello World')
ちなみに、同じプログラムをRubyで書くと、
1: p "Hello World"
1.6. Java言語の「キーワード」
もう一度、先程のJava言語のコードを見てみよう。
1: class Main { 2: public static void main(String[] args) { 3: System.out.println("Hello World"); 4: } 5: }
プログラムに出てくるclass, public, static, void などは Keywords と呼ばれ、どれも重要な意味がある。
しかし、これらの keyword の意味を理解するためには、Java言語をある程度学んでからでなくては難しい。このため、この授業では最小限度の解説に止める。
なお、keywordは予約語(Reserved word)とも言う。Java言語本体が利用することが予約されており、自分のプログラムの変数名、関数名等に利用することはできないことを、覚えておこう。
1.7. いまはテンプレートとして考えよう
- class等の予約語を理解するのは後まわしにし、テンプレートとして利用してみよう。
1: class Main { 2: public static void main(String[] args) { 3: System.out.println("JavaプログラムI"); 4: } 5: }
- このように、コードの3行目を変更することで、別の文字列が出力される。
- 別の例をみよう。
1: class Main { 2: public static void main(String[] args) { 3: System.out.println("情報処理技法"); 4: System.out.println(1 + 2); 5: System.out.println(Math.PI); 6: System.out.println(new StringBuilder("情報処理技法").reverse()); 7: } 8: }
- このように、プログラムには 複数の行を書く ことができる。
2. 字句構造:プログラミングの基礎知識 #02
2.1. 追加資料
- 日本語資料としておすすめ
2.2. プログラムに使う文字(Unicode)
2.2.1. テキストファイルとUnicode
- プログラムはテキストファイルで作成
- 「テキスト=文字」からなるファイル
- 文字コード(文字を数値で扱うための決まり)
2.2.2. キーボードにある記号の読み方
記号 | 一般的な読み方 | 英語スペル | JIS規格の名称 |
---|---|---|---|
( | 開き括弧 (かっこ) | left paren、open parenthesis | 左小括弧 |
) | 閉じ括弧 (こっか) | right paren、close parenthesis | 右小括弧 |
{ | 開き中括弧 | left brace、open brace | 左中括弧 |
} | 閉じ中括弧 | right brace、close brace | 右中括弧 |
[ | 開き大括弧 | left bracket、open bracket | 左大括弧 |
] | 閉じ大括弧 | right bracket、close bracket | 右大括弧 |
= | イコール | equals | 等号 |
+ | プラス | plus | 正符号 |
- | マイナス 、ハイフン、ダッシュ (本当は別物) | hyphen、dash | ハイフン、負符号 |
* | アスタリスク スター コメ印 掛算記号 | asterisk | アスタリスク |
/ | スラッシュ 、割算記号 | slash | 斜線 |
\(¥) | バックスラッシュ | backslash | 円記号 |
< | 小なり記号 | less than | 不等号(より小) |
> | 大なり記号 | greater than | 不等号(より大) |
' | シングルクウォート 、アポストロフィ、ちょん | single quote | シングルクォート、アポストロフィー(本来は別もの) |
` | バッククオート | back quote | アクサングラーブ |
" | ダブルクォート 、ちょんちょん | double quote | 引用符 |
, | カンマ | comma | コンマ、セディユ |
. | ピリオド 、 ドット 、ポイント | period、dot、point | 終止符 |
; | セミコロン | semicolon | セミコロン |
: | コロン | colon | コロン |
? | はてな記号 、クエスチョン・マーク | question mark | 疑問符 |
! | びっくり記号 | exclamation | 感嘆符 |
# | シャープ記号 、ナンバー、ハッシュ | number sign、pound sign、hash | 番号記号、井桁(いげた) |
$ | ドル記号 | dollar sign | ドル記号 |
% | パーセント | percent | パーセント |
& | アンド記号 、アンパサンド | ampersand、and sign | アンパサンド |
~ | チルダ 、にょろ記号 | tilde | 波線、波線符号 |
_ | アンダースコア | underscore | アンダライン |
^ | ハット 、サーカムフレックス | hat, circumflex | アクサンシルコンフレックス、キャロット |
| | バー 縦棒 | vertical bar | 縦線 |
2.2.3. 改行文字
- プログラムは複数の行からなる
- 1行は「改行文字」で終わる(3.4.Line Terminators)
- 改行文字は目で見えないが、そこにあるもの
- <CR>…改行文字
abc<CR> defgh<CR> ij<CR>
- 改行の入力
- キーボードのEnterキー
- 改行の削除
- BSキー
2.2.4. 空白文字
- 空白は目に見えない文字
- _…空白文字
__abc<CR> ___de_fgh<CR> _i_j_<CR>
- 空白文字は改行文字を含む
- 空白の利用目的
- 単語を区切る
- プログラムを見やすく整える
- タブ(TAB)
- 8文字毎に桁を揃える特殊な空白
- 4文字や2文字のことも
- 近年は使わないことが望ましい
- 8文字毎に桁を揃える特殊な空白
2.3. コメント(Comments)
- プログラムに自然言語(日本語や英語など)で 3.7.Comments を記述できる
- コメントは人間が読むためのものであり、コンピュータは読み飛ばす
- コメントを適切に書くことで、 人間 が読みやすいプログラムになる
- コメントの書き方は2通りある
- 行コメント
- 範囲コメント
1: class Main { 2: public static void main(String[] args) { 3: // この行はコメント 4: 5: /* 6: この 7: 範囲は 8: コメント 9: */ 10: 11: // System.out.println("表示されません"); 12: // System.out.println("これも表示されません"); 13: } 14: }
- 書きやすいので、複数行のコメントでも行コメントを使うことが多い
- ちなみに、pythonには行コメントのみ
# comment a = 1 # comment
- ちなみに、rubyの場合
- 範囲コメントはあるが、使うのは稀
# comment p 123 =begin p 'ABC' p 'DEF' =end p 456 # comment
2.4. 識別子(Identifier)
2.4.1. 識別子(Identifier)とは
- あるモノと、他のモノとを区別できるようにするための仕組み
- 識別子の具体例
- 電話番号
- 学籍番号
- 銀行の口座番号
- メールアドレス など
- 普段利用している「名前」は識別子になるか?
- 同姓同名!
- 新宿駅!
- 識別子は情報処理システムで情報を扱う場合に、重要な概念の一つ
- ある情報と他の情報を区別するために必要
2.4.2. プログラミングと識別子
- プログラムではある概念(変数やデータの種類、関数など)を扱うために名前を使う
- 名前は単なる名前ではなく、識別子である
- appleとringo
- ある識別子が他の識別子と同じであると判断されるためには、一字一句同じ名前である必要がある
- 逆に言えば、一字一句同じ名前であれば、それらは「同じもの」である
- 似たような概念であっても別なものとして扱いたい場合は、必ず別の名前をつけなくてはならない
- apple1
- apple2
- apple3
- 似たような概念であっても別なものとして扱いたい場合は、必ず別の名前をつけなくてはならない
2.4.3. 識別子の使い方
- 予め定義されている識別子
- プログラミング言語が予め定義している名前(予約語)
- プログラマーが新たに定義する識別子
- 何らかの情報につける名前(=変数名など)
- 何らかの処理につける名前(=関数名など)
- 識別子はその意味を定義してから使う
- 意味の定義の仕方はプログラミング言語によって様々
3. 字句構造:プログラミングの表記法 #03
3.1. 記号・区切り文字・演算子
3.1.1. Javaの識別子(Identifier)とキーワード(Keywords)
3.1.2. 参考:紛らわしい文字と数字
- 似てる文字の悪夢
- 似ている文字
- 0とOとo
- bと6
- 1と7とlとIと!
- gと9とq
- aとoとe
- mとrn
- ‘と”と` などなど
- 例
- 「Al(男性名アル)」と「AI(人工知能)」
- 「burn(やけど)」と「bum(浮浪者)」
- 「boat(ボート)」と「boot(靴)」
- 似ている文字
- スペルミス
- 一見同じに見えるけど(スペルミス・大文字小文字の悪夢)
- Hello Hallo Halo
- print と plint
- system と sistem
- Japan と japan
- JAVAとJava
- 一見同じに見えるけど(スペルミス・大文字小文字の悪夢)
- 同じ?違う?
- 次の中で「東京女子大」と書かれているものはどれか?
- Tokyojoshidai
- Tokyouzyosidai
- Toukyoujoshiidai
- 中鉢(ちゅうばち)をローマ字で書いたとき、正しいのは?
- Chubachi
- Tyuubati
- Chuubati
- 本屋
- honnya
- hon'ya
- 次の中で「東京女子大」と書かれているものはどれか?
- 全角・半角問題
- 日本語特有の問題
- 「あい うえお」と「あい うえお」
- @マークと@マーク
- ”こんにちは” と“こんにちは”
- To_Do と To_Do
- 日本語特有の問題
3.1.3. 区切り文字(Separators)
- 仕様
- これらはプログラムの文字列の区切りを表す。
- プログラムそのものも文字列でできている。
( ) { } [ ] ; , . ... @ ::
- abc <=> a,b,c <=> a,bc
例えば,次の文字列は
abc.def(gh[10],ijk[-2]);
次の通り区切って取り扱われる。
abc . def ( gh [ 10 ] , ijk [ -2 ] ) ;
3.1.4. 演算子(Operators)
- 仕様
- 1つ以上の記号を組み合わせた、異なる意味を持つ演算子が定められている。
例
演算子 意味 = 代入 == 等しい > 〜より大きい <= 以下 % 割算の余り
3.1.5. 区切り文字と空白文字
- 区切り文字の効果
- abc <=> a,b,c <=> a,bc
- 前節の区切り文字とあわせ、次のプログラムは
a=0;if(a>=-10){return(3.14);}
- 次の通り区切られる(プログラムの意味は気にしないこと)
a = 0 ; if (a >= -10 ) { return ( 3 . 14 ) } ;
- なお、「3/./14」はひと塊で意味を持つ数値であるので、 実際には「3.14」として取り扱われる。
- 次の通り、区切り文字の前後には好きなだけ
空白文字(3.6. White Space)を入れることができる。
- ただし、「3.14」 のピリオドの前後には入れられないなど、 例外はある
1: System.out.println(3.14);
- とても自由に空白文字を入れても動作する
1: System 2: . 3: out 4: 5: .println 6: ( 7: 3.14 8: );
- ちなみに、pythonの場合
print( "pi=" + str(3.14 ))
print ( "pi=" +str( 3.14 ) )
Javaの一文は、セミコロンで終了する。このことにより、 Javaでは比較的自由に改行や空白を入れることができる。
なお、改行や空白が自由に使えることは、プログラムを書く人によって スタイルがばらばらになるというデメリットも発生する。
3.2. 文(Statement)
- 仕様
- プログラムはいくつかの文からなる
- Javaでは、文を「;」で区切る(日本語の「。」と同じ感覚)
- 文の例
- System.out.println(“…”);
- int i = 0;
- ruturn;
Figure 1: プログラムはいくつかの文からなる
3.3. 複合文(Block statement)
- いくつかの文をまとめてブロックにすることができる(複合文:Block statement)
Figure 2: プログラムはいくつかのブロックからなる
- ブロックの中にブロックを作ることができる
- 入れ子構造(Nested Structure)
- 入れ子構造はプログラムの基本構造である
- プログラムはブロック(Block)(とStatement)を入れ子構造にして構成する
- 入れ子構造(Nested Structure)
- Javaでは「{」と「}」でブロックを作る
// 1 2 3 { System.out.println("block1"); } { System.out.println("block2"); } { System.out.println("block3"); { System.out.println("block3-1"); } { System.out.println("block3-2"); } } { System.out.println("block4"); { System.out.println("block4-1"); { System.out.println("block4-1-1"); } { System.out.println("block4-1-2"); { System.out.println("block4-1-2-1"); } } } { System.out.println("block4-2"); } }
Figure 3: 入れ子構造
3.4. 字下げ(indent)の重要性
- 先程の入れ子構造のプログラムはこの様に書くこと「も」できる。
1: {System.out.println("block1");}{System.out.println("block2");}{System.out.println("block3");{System.out.println("block3-1");}{System.out.println("block3-2");}}{System.out.println("block4");{System.out.println("block4-1");{System.out.println("block4-1-1");}{System.out.println("block4-1-2");{System.out.println("block4-1-2-1");}}}{System.out.println("block4-2");}}
- 字下げを適切に用いないと、プログラムの入れ子構造はとてもとても分かりにくくなる。
- 字下げを正しく記述しないとエラーとなるプログラミング言語(python)もあるが、Javaでは自分で正しく字下げをする必要がある。
- この授業では、1段階の字下げを空白2文字分とする。
- 字下げが理解でき、正しくできるようになるかどうかが、プログラミングを習得できるかどうかの鍵になる(と言っても過言ではない)
Pythonの場合
- インデントでブロックを表す
def fibonacci_iter(n): a=1 b=1 if n==1: print('0') elif n==2: print('0','1') else: print('0') print(a) print(b) for i in range(n-3): total = a + b b=a a= total print(total) fibonacci_iter(8)
Rubyの場合
- def ~ end, for ~ end など
- { } を用いる場合もある
def num(n) return 1 if n == 1 return 1 if n == 2 num(n-1) + num(n-2) end for i in 1..40 print "#{num(i)} " end
3.5. プログラムはブロックの組み合わせ
- プログラムは「積み木」のようにブロックを組み合わせて作成する
- 一つ一つのブロックは何らかの意味のまとまりを持つ
- 小さな積み木をどんどん積み重ね、大きなプログラムにする
4. 字句構造:型と様々な直値 #04
4.1. 情報量と型
4.1.1. 情報量(bit)のおさらい
- 2進数で整数を扱う場合
bit数 | 扱える情報の個数 | 正の整数とすると | 負の整数も扱うなら | 扱える情報の例 |
1 | 2こ | 0,1 | -1,0 | 真と偽/yes no/true false |
2 | 4こ | 0,1,2,3 | -2,-1,0,1 | 方位 |
3 | 8こ | 0,1,2,3,4,5,6,7 | -4, -3, -2, -1, 0, 1, 2, 3 | 月,火,水,木,金,土,日 |
4 | 16こ | 0~15 | -8~7 | 十二支 |
8 | 256こ | 0~255 | -128~127 | A~Z、a~z、数字、記号 |
16 | 65536こ | 0~65535 | -32,768~32,767 | よく使う日本語の文字 |
32 | 42億9496万7296こ | 0~4,294,967,295 | -2,147,483,648~2,147,483,647 | 地球の年齢には少し足りない |
64 | 1844京6744兆737億955万1616こ | 0 ~ 18,446,744,073,709,551,615 | -9,223,372,036,854,775,808 ~9,223,372,036,854,775,807 | とても大きな数・・・ |
- 2進数で実数を扱う場合
bit数 | 名称 | 表現できる範囲 | 精度(参考) | 扱える情報の例 |
32 | 単精度浮動小数点 | およそ±10-38 〜 ±1038 | 10進数で7桁程度 | とてもとても大きな数からとてもとても小さな数 |
64 | 倍精度浮動小数点 | およそ±10-308 〜 ±10308 | 10進数で16桁程度 | とてもとてもとてもとても・・・(以下略 |
4.1.2. 「型(type)」とは何か
- Chapter 4. Types, Values, and Variables
- プログラムで情報を扱いたいとき、単にbit数だけを決めても不十分
- bit数で扱える情報の個数は決まる
- ただしその情報の扱い方を別途決めておかなくてはならない
- 正の整数として見るのか
- 負の整数として見るのか
- 実数(浮動小数点数)としてみるのか
- (更に言えば、画像として扱うのか、音声として扱うのか・・・・)
- プログラムでは情報の量やその取り扱い方をまとめて「型(Type)」と言う
4.1.3. Javaの基本型(primitive type)
- 基本型
- 基本型の名前の最初の文字は「アルファベット小文字」になっている
データ型 | bit数 | 範囲 |
boolean(ブーリアン) | 1(本当は違うけど) | true / false (トゥルー・フォルス) |
byte(バイト) | 8 | -128~127 |
short(ショート) | 16 | -32768~32767 |
int(インテジャー or イント) | 32 | -2147483648~2147483647 |
long(ロング) | 64 | -9223372036854775808~9223372036854775807 |
float(フロート) | 32 | 単精度浮動小数点数 |
double(ダブル) | 64 | 倍精度浮動小数点数 |
char(キャラクター or チャー) | 16 | Unicode文字 (\u0000~\uFFFF) |
void(ボイド) | --- | (型が)無い ※特殊 |
4.1.4. 参照型
Javaでは基本型の他に「参照型(ReferenceType)」がある。イメージとして、基本型を組み合わせて参照型を作る。言わば、基本型に対する応用型である。更に、参照型は他の参照型を組み合わせることもできるので、複雑な情報を取り扱うことができる。
4.2. 数値の直値
4.2.1. 数値(Value)の書き方
- 「数字(number)」と「数値(value)」の違い
- 数字は文字、数値は値
- 数値をプログラムに書く
- 数字、ピリオド、マイナス記号等を用いて直接書く(=直値)
- 直値(literal)
- 数値の直値にも「型」がある
4.2.2. 整数型
- int型整数(デフォルト)
- 1
- -123
- 3776
System.out.println(1); System.out.println(-123); System.out.println(3776); System.out.println(1234567890); System.out.println(2147483647); // System.out.println(2147483648);
- long型整数(アルファベットのLをつける)
- 1 L
- 12345678901234567890123456789 L
System.out.println(2147483648L); System.out.println(1234567890123456789L); System.out.println(9223372036854775807L); // System.out.println(9223372036854775808L);
- Lをつけないとエラー。
class Main { public static void main(String[] args) { System.out.println(2147483648L); } }
4.2.3. 実数型
- double型実数(デフォルト:Dをつけてもつけなくても構わない)
- 1.0
- -3.1415926534
- .375 (1の位が0なら省略できる)
- 6.02214076E+23 (アボガドロ定数6.02214076✕1023の浮動小数点表記)
1: System.out.println(1.0); 2: System.out.println(-3.1415926534); 3: System.out.println(.375); 4: System.out.println(6.02214076E+23);
- float型実数(アルファベットのFをつける)
- -1.0F
- 3.14F
- 3.141592F
1: System.out.println(-1.0F); 2: System.out.println(3.14F); 3: System.out.println(3.141592F);
,#+RESULTS:
-1.0 3.14 3.141592 1.0 -3.1415926534 0.375 6.02214076E23
要するに、数字の他にピリオドがなければint、あればdoubleと扱われると覚えれば良い。
class Main { public static void main(String[] args) { System.out.println(1E+2); // 1*10^2 = 1*100 = 100 System.out.println(1E+1); // 1*10^1 = 1*10 = 10 System.out.println(1E+0); // 1*10^0 = 1*1 = 1 System.out.println(1E-1); // 1*10^(-1) = 1*0.1 = 0.1 System.out.println(1E-2); // 1*10^(-2) = 1*0.1 = 0.01 System.out.println(6.02214076E+23); } }
4.3. 真偽値の直値 #05
4.3.1. 真偽値型
- 真偽値型
- 書き方
true
false
1: System.out.println(true); 2: System.out.println(false);
4.4. 文字の直値
4.4.1. 文字の直値
- 文字の直値
- 文字の直値はシングル・クォーテーション記号で囲む
- char型
- 'a' 「a」という文字(半角)
- '字' 「字」という文字(全角)
- '华' 中国語簡体字の文字(「華」)
- char型
1: System.out.println('a'); 2: System.out.println('字'); 3: System.out.println('华');
「文字」と「文字列」は異なる!文字は1文字だけ。文字列は何文字でも。普段のプログラミングでは圧倒的に文字「列」を使うことが多い(後述)。
4.4.2. 文字の直値とエスケープシークエンス
- エスケーシーケンス
- 文字は「シングルクォーテーション」で囲むという規則のとき、
- 「
'
」という文字(シングルクォーテーション)自体はどうあらわす?
- 「
'''
こんな書き方はできない!- 2つ目のシングルクォーテーションが 文字の終わり を示してしまいエラーとなる
1: System.out.println('''); // Error!
- 「文字の終わりじゃなくって、 シングルクォーテーションという文字である」こと示すために、 エスケープ・シークエンス(escape sequence) を使う
- エスケープとは、「何らかの意味」から「免れる」こと
- 「文字の終わり」という意味を打ち消す
- シングルクォーテーションをエスケープ・シーケンスで表す方法
'\''
バックスラッシュ+シングルクォーテーション
1: System.out.println('\''); // OK
- すると、「
\
(バックスラッシュ)」記号自体はどう表すの?'\\'
バックスラッシュ+バックスラッシュ
1: System.out.println('\\'); // OK
- これは良い仕組みだ!他にも拡張しよう!!
'\n'
改行(Enter)のエスケープシークエンス'\t'
タブ(Tab)のエスケープシークエンス他にもいろいろある(が、めったに使わない)
1: class Main { 2: public static void main(String[] args) { 3: System.out.print('\t'); 4: System.out.print('a'); 5: System.out.print('\n'); 6: } 7: }
- Unicodeもエスケープシーケンス(の16進数)で表してしまえ!
1: System.out.print('\u2708'); 2: System.out.print('\uD392'); 3: System.out.print('\u0A09');
16進数に用いるabcdefは大文字・小文字を問わない
- 空の文字はエラー
- ''
1: System.out.println(''); // Error!!
4.4.3. 参考:ASCIIコード表
4.5. 文字列の直値
4.5.1. 文字列の直値
- 文字列の直値
- 文字列の直値はダブル・クォーテーションで囲む
"こんにちは" |
「こんにちは」という文字列 |
"あけましておめでとう\nことしもよろしく" |
改行を含んだ文字列 |
"\u6771\u4eac" |
「東京」のUnicode表現 |
"文字列は\"で囲む" |
ダブル・クォーテーションを含む文字列 |
"🥺" |
絵文字は1文字でも文字列(2文字相当) |
"" |
空文字列(長さ0の文字列) |
class Main { public static void main(String[] args) { System.out.println("こんにちは"); System.out.println("あけましておめでとう\nことしもよろしく"); System.out.println("\u6771\u4eac"); System.out.println("文字列は\"で囲む"); System.out.println("文字は'で囲む"); System.out.println("🥺"); System.out.println(""); } }
空文字( ''
)はエラーとなるが、空文字列( ""
)はエラーとならない。なぜだろう?
4.6. ヌル値の直値
4.6.1. ヌル値
- ヌル値
- ヌル値とは?
- 整数型の0に相当する
- いわば参照型のための特殊な0の表現
1: System.out.println(null);
5. 変数の宣言・代入・参照・初期化と名前 #05
5.1. 変数(Variable)とは?
- 変数
- 変数とは?
- プログラムにおける情報の入れ物
- 代入とは?
- 変数は代入をすることで値が変わる
- 参照とは?
- 変数の値を読み出すこと
- 変数と型
- 変数には型が与えられる
- 異なる型の値は、代入できない
5.2. 変数の宣言(declaration)
- 「変数を宣言する」とは?
- 〇〇という 名前 で 〇〇という 型 の変数を用意してね、 と指示すること
- ある名前に「それは変数だよ」という意味を与えること
int i; // 整数型のiという変数を宣言 double pi; // 倍精度実数型のpiという変数を宣言 char ch; // 文字型のchという変数を宣言 boolean flag; // 真偽値型のflagという変数を宣言
- 同じ型の変数を複数宣言することもできる
int i,j; double x,y,z;
- 宣言をしないで参照することはできない
System.out.println(ch); // Error!
- 予約語を変数名にすることはできない
int class; // classは予約語 double public; // publicは予約語 boolean static; // staticは予約語
5.3. 変数への代入(assignment)と参照(reference)
- 代入
- 宣言した変数に値を設定すること
- 参照
- 変数の値を取得すること
int i; // 整数型の変数iを宣言 i = 27; // 変数iに27を代入 System.out.println(i); // 変数iを参照
5.4. 変数の初期化(initialize)
- 変数を宣言したら、原則、その変数を 初期化 する
- 初期化とは、変数を宣言して最初に行う代入
- 代入する値を 初期値 という
- 変数を初期化する理由
- 変数が参照できることを保証する
- 宣言しただけの変数を参照することはできない
- 変数を初期化しないで参照してはならない
- コンパイル時にエラーとなる
- 変数の宣言と初期化は同時に行うことができる
int x = 0; // 変数xを宣言し初期化 System.out.println(x); // 変数xを参照できる
int x; // 変数xを宣言して初期化しない System.out.println(x); // 変数xを参照 -> Error!
int x; // 変数xを宣言して初期化しない x = -1; // 代入をすれば、 System.out.println(x); // 変数xを参照 -> OK
double pi = 3.14; // 変数piを宣言し初期化 System.out.println(pi); // 変数piを参照できる
boolean flag = true; // 変数flagを宣言し初期化 System.out.println(flag); // 変数flagを参照できる
byte b = 3; int i = -11; long l = 1245678901234567890L; float f = 9.80665F; // 標準重力加速度(m/s^2) double d = 2.99792458E8; // 真空中の高速(m/s) System.out.println(b); System.out.println(i); System.out.println(l); System.out.println(f); System.out.println(d); char ch = '字'; boolean flag = true; System.out.println(ch); System.out.println(flag);
- 宣言は一度だけしておけば、何度でも代入できる。
int i = 0; // 変数iを宣言し初期化 System.out.println(i); // 変数i = 0 i = 1; // 変数iに代入 System.out.println(i); // 変数i = 1 i = 2; // 変数iに代入 System.out.println(i); // 変数i = 2
- 複数の変数の宣言と初期化の方法
- こういう方法もある、と
double x, y, z; x = y = z = 12.345; System.out.println(x); System.out.println(y); System.out.println(z);
5.5. 変数の名前空間(name space)
- 変数の「定義域」とも呼ばれる
- その変数が有効な範囲
- 変数の名前は「借り物」
- 借りたものは必ず返す
- そうでないと、同じ名前をプログラムの他の場所で利用したいときに困る
- 名前空間はブロックと一致する
- あるブロックで定義した変数は、そのブロックが終了するまで有効
- あるブロックで定義した変数は、内側のブロックでも有効
- あるブロックで定義した変数は、外側のブロックでは無効
- 同じ名前の変数を、同じブロックで複数回宣言することはできない。
int i = 0; // 変数iを宣言し初期化 System.out.println(i); // 変数i = 0 int i = 1; // 変数iを再び宣言 -> Error!! System.out.println(i); // 変数i = 1
この間違いは初心者あるあるなので注意!
- ブロックが異なれば、同じ名前を使える(ブロック=名前空間)。
{ int i = 0; // 変数iを宣言し初期化 System.out.println(i); // 変数i = 0 } { int i = 1; // 変数iを再び宣言 -> OK System.out.println(i); // 変数i = 1 }
- 外側のブロックで宣言した変数は、内側でも使える。
{ int out; { out = 10; System.out.println(out); } }
- 内側のブロックで代入した値は外側で参照できる。
{ int out; { out = -3; } System.out.println(out); }
- 内側で宣言した変数は、外側では使えない。
{ { int in = -10; } System.out.println(in); // Error!! }
- 同じ名前の変数で上書きはできない (できても良いと思うのだが・・・)。
1: { 2: int x = 1; 3: { 4: int x = -1 // Error!! 5: System.out.println(x); 6: } 7: System.out.println(x); 8: }
5.6. 変数の名前の付け方
- 変数名
- 変数には必ず「名前」をつける(=命名)
- 変数名は識別子である
- 命名規則(コーディング規約)
- 変数の名前の付け方には規則がある
- 基本的にはアルファベットと数字(アンダースコア等の記号は使わない)
- 先頭はアルファベット小文字
- 2つ以上の単語を使うときは、単語の先頭だけをアルファベット大文字にする
- ○ hello
- ○ helloWorld
- ○ helloWorld2
- × 2helloWorld
- × Hello
- × hello_world
- スネークケース vs キャメルケース
- これらの規則に違反してもエラーにはならない
- あくまでも人間のためのルール
- 守らないとどうなるか?
- 「こいつJavaわかってないんじゃね?・・・」と言われるダケ
- 変数名にはUnicodeを用いることもできるが、非推奨
double π = 3.14; System.out.println(π); int 日本語 = 10; System.out.println(日本語); // int 😜❤🤷 = -99; // Error!!
6. 式の評価と数値の演算 #06
6.1. 式の評価
- 式(Expression)
- 計算式
- 15. Expressions
- 式の評価(Evaluation)
- 式を計算すること
- 文のなかに「式」が埋め込まれる
- 次の「1 + 2」が式
System.out.println(1 + 2);
- 式を評価するとは?
- 計算の結果で式を置き換える
System.out.println(3);
6.2. 変数の評価
- 変数の評価
- 変数の値を参照し変数を置き換えること
int x = 123; System.out.println(x);
- 変数を評価する
System.out.println(123);
6.3. 数値の演算
- 整数の加算・減算・乗算
System.out.println(1 + 2); System.out.println(3 - 4); System.out.println(5 * 6);
- 整数の除算
System.out.println(5 / 3); // 商 System.out.println(5 % 3); // 余
System.out.println(43871028 / 732); // 商 System.out.println(43871028 % 732); // 余 System.out.println(59933 * 732 + 72); // 検算
- 実数の加算・減算・乗算(他方が整数であれば実数に変換)
System.out.println(2 * 3.14 * 5.7); System.out.println(0.1 + 0.9); System.out.println(2 - (1.9 + 3.2)); System.out.println(6.+.6);
- 実数の除算(割る数・割られる数のどちらかが実数)
System.out.println(5.0 / 3); System.out.println(2 / .037); System.out.println(1e+7 / 10); // 1e+7 = 10,000,000
- 実数の計算の例
System.out.println(5 / 3); System.out.println(5 % 3); System.out.println(5.0 / 3); System.out.println(5D / 3); System.out.println(5F / 3); System.out.println(5.0 % 2.5);
6.4. 変数の演算と結果の代入
- 変数の値を参照し、計算結果を別の変数に格納
int height = 7; int width = 3; int area = height * width; System.out.println(area);
- 変数の値を参照し、計算結果を同じ変数に格納
int x = 5; System.out.println(x); x = x * 7; System.out.println(x);
- インクリメント・デクリメント演算子
int i = 3; System.out.println(i); i ++; // i = i + 1 System.out.println(i); i --; // i = i - 1 System.out.println(i); // helloWorldILoveYou = helloWorldILoveYou + 1; // helloWorldILoveYou ++;
- 代入演算子
int i = 3; System.out.println(i); i += 2; // i = i + 2; System.out.println(i); i -= 1; // i = i - 1; System.out.println(i); i *= 3; // i = i * 3; System.out.println(i); i /= 4; // i = i / 4; System.out.println(i);
7. 論理演算・比較演算 #07
7.1. 論理演算子(logical operators)
真偽値(boolean型の値)に対して行う演算
System.out.println(true); System.out.println(false);
- 否定(not)
a | !a |
true | false |
false | true |
System.out.println(!true); System.out.println(!false);
- 論理積(and)
a | b | a && b |
true | true | true |
true | false | false |
false | true | false |
false | false | false |
System.out.println(true && true); System.out.println(true && false); System.out.println(false && true); System.out.println(false && false);
- 論理和(or)
a | b | a||b |
true | true | true |
true | false | true |
false | true | true |
false | false | false |
System.out.println(true || true); System.out.println(true || false); System.out.println(false || true); System.out.println(false || false);
- 変数(boolean型)を用いることもできる
boolean f1 = true; boolean f2 = false; System.out.println( !f1); System.out.println( f1 && f2); System.out.println( f1 || f2);
7.2. 比較演算子(comparison operators)
演算子 | 概要 | 例 |
---|---|---|
== | 左辺と右辺が等しければtrue | 5 == 5 |
!= | 左辺と右辺が等しくなければtrue | 5 != 5 |
< | 左辺が右辺より小さければtrue | 5 < 7 |
<= | 左辺が右辺以下であればtrue | 5 <= 3 |
> | 左辺が右辺より大きければtrue | 7 > 5 |
>= | 左辺が右辺以上であればtrue | 5 >= 7 |
- 等しい(==)
System.out.println( 3 == 3 ); System.out.println( 3 == 5 ); System.out.println( true == true); System.out.println( true == false);
- 等しくない(!=)
System.out.println( 3 != 3 ); System.out.println( 5 != 5 ); System.out.println( true != true); System.out.println( true != false);
- より小さい(小なり) (<)
System.out.println( 2 < 3 ); System.out.println( 2 < -3 );
- 以下(<=)
System.out.println( 2 <= 3 ); System.out.println( 2 <= -3 );
- より大きい(大なり) (>)
System.out.println( 2 > 3 ); System.out.println( 2 > -3 );
- 以上(>=)
System.out.println( 2 >= 3 ); System.out.println( 2 >= -3 );
- 変数を用いることもできる
int i = 8; int j = -3; System.out.println( i == 8); System.out.println( i + j == 5); System.out.println( i < 10); System.out.println( i >= j);
- 比較演算の結果をboolean型の変数に代入できる
boolean flag = 3 < 5; System.out.println(flag);
7.3. 比較演算子と論理演算子の組み合わせ
- 比較演算子と論理演算子は組み合わせて使うことができる
- 比較演算の結果は真偽値(trueかfalseのどちらか)
- よって、論理演算(andやor、not)と組み合わせられる
- 比較演算子の組み合わせ
System.out.println(true == true ); System.out.println( 2 < 5 ); System.out.println(( 2 < 5 ) == true );
- 論理演算子との組み合わせ
System.out.println((2 < 3) && ( 3 < 4)); System.out.println((2 < 3) || ( 3 <= 4));
値を比較演算子で評価した結果はboolean型となる。一方、論理演算子はboolean型同士の演算をする。これらを組み合わせて、より複雑な論理式を作ることができる。
プログラムは細かいパーツの組み合わせである。「演算子による計算結果は数値だね、そしたら、比較演算子と組み合わせられるね!」、「比較演算子の比較結果は真偽値だね、そしたら、論理演算子でいくつも組み合わせられるね!」という組み合わせの発想が大切となる。
比較演算子は基本型にしか使えない(と覚えておこう)。例えば、文字列型の値を比較する際に ==
を使うと、予期しない結果になることがある。コンパイルは通るので、間違うと深刻なバグの原因となり得る。なお、文字列型には比較をするための専用の方法があるので、別途、解説する。
- 変数と組み合わせる
int score = 95; System.out.println(score > 60);
- 少し複雑な例
int average = (87 + 63 + 76 + 91) / 4; System.out.println(average); System.out.println(average >= 60);
- 次のコードはエラー
- 理由を知りたい人は「Java 演算子 優先順位」で検索
System.out.println(! 10 > 5);
8. 型変換 #08
8.1. 型変換(type casting)
- 異なる型の値同士を変換することができる
- これを 型変換(型キャスト) と言う
- 基本型で扱える数値の範囲
- byte < short < char < int < long < float < double
- 参照
8.2. 拡大変換(widening conversion)
- 拡大変換
- 小さな型を大きな型に変換すること
- 例) int から long, byte から float
- 暗黙的型変換(Implicit type conversion)
- 拡大変換はどのような場合も上手くいく
- プログラマーが変換せよと指示しなくても、暗黙的に行われる
int i = 65536; long l = i; System.out.println(i); System.out.println(l);
float f = 3.14F; double d = f; System.out.println(f); // 3.14 System.out.println(d); // 3.140000104904175
int i = 123456; double d = i; System.out.println(i); // 123456 System.out.println(d); // 123456.0
- char型からの変換時は、文字コード(数値)として扱われる
char c = 'A'; int i = c; System.out.println(i); // 65
大は小を兼ねる!
8.3. 縮小変換(narrowing conversion)
- 型変換がうまくいかない場合(大きな型から小さな型への変換)
- コンパイル時にエラー になる。
short s = 654; byte b = s; // Error! System.out.println(s); System.out.println(b);
double d = 3.14; int i = d; // Error! System.out.println(d); System.out.println(i);
- 縮小変換
- 大きな型を小さな型に変換すること
- 例) long から int, double から float
- 縮小変換が上手くできる場合
- 変換先の型に収まる値かどうか
- 例
- int型の300はshortに変換できるか?
- shortの範囲は-32768~32767なので、OK
- int型の50000はshortに変換できるか?
- short型の範囲に収まらないので、NG
- double型の3.14はintに変換できるか?
- 小数点以下の値が格納できないので、NG
- int型の300はshortに変換できるか?
- 縮小変換をプログラムで行う場合、 明示的に 記述する
- すべての場合を考えるとうまくいかないけど、この場合についてはうまくいく、ということをプログラマーがコンパイラーに指示すること
- 例
- 今使っている型はint型であるが、中身は~128~127の範囲に収まるので、byte型に変換しても差し支えない
- 今使っている方はdouble型であるが、その整数部分だけをint型に収めたい
- 明示的型変換(Explicit type conversion)
- 大きな型から小さな型への変換は問題が発生する場合がある
- プログラマーがそれを知った上で意図的に型変換することを「明示的型変換」という
- 型変換の明示法
- 型の名前を()で囲む
- コンパイルエラーはでなくなるが、 期待通りに変換できているかプログラマが注意する必要がある
int i = 100; byte b = (byte) i; System.out.println(b);
- 桁溢れ(over flow)する場合
// 00000000 ~ 11111111 (2進数) // -128 ~ 127 (10進数) // 11111111 + 1 = 100000000 (9bit) int i = 128; byte b = (byte) i; System.out.println(b);
double pi = 3.14; int i = (int) pi; System.out.println(i);
double d = 1.0E36; float f = (float)d; System.out.println(f);
- 直感と異なる型変換が行われる場合
- 期待通りかどうかはその時次第
int i = 128; byte b = (byte) i; System.out.println(b); // -128
double d = 1.0E39; float f = (float) d; System.out.println(f); // Infinity
double d = 1.0E36; int i = (int)d; System.out.println(i); // 2147483647
- 文字コードから文字への変換
int i = 66; char c = (char)i; System.out.println(c); // B
9. 文字列型(String) #09
9.1. 文字列型
- 文字列型は参照型(reference type)に分類される型である。
- 基本型(primitive type)ではない。
- 参照型は、基本型の組み合わせで作られる
- プログラマが自ら定義することができる
- Java言語には多くの型が予め用意されている(library)
- 文字列型以外にもいっぱいある(配列型とか、ファイル型とか・・・)
- 参照型の名前の最初の文字は「アルファベット大文字」になっている
- 基本型は小文字
データ型 | データそのもののbit数 | 範囲 |
String(ストリング) | 不定(大きさは可変) | Unicode文字(char)の列 |
- 文字列の直値を文字列型の変数に代入
String str = "こんにちは"; System.out.println(str);
String str = "文字列"; // 変数strを宣言し初期化 System.out.println(str); // 変数strを参照できる
- 長さ0の文字列を代入する
String str = ""; // 空文字列 System.out.println(str);
- 参照型である文字列型にはnullを代入できる
String str = null; System.out.println(str);
""は長さ0の文字列が ある ことを示すのに対し、null文字列は文字列が ない ことを示す。
9.2. 文字列の演算
- 文字列の加算
- 文字列は「+」演算子で加算(連結; concatinate)ができる
String a = "Hello"; String b = "World"; String str = a + b; System.out.println(str);
String a = "Hello"; String b = "World"; String space = " "; String str = a + space + b; System.out.println(str);
- 文字列の引算・乗算・除算はできない
String a = "Hello"; String b = "World"; // System.out.println(a - b); // Error!! // System.out.println(a * 2); // Error!! // System.out.println(a / b); // Error!!
- 文字列と基本形の加算
- 一方が文字列であれば、もう一方は 文字列に変換 される
- これは文字列の加算(連結)の際に行われる特別な、型の拡大変換である
int a = 2750; String b = "円"; String str = a + b; System.out.println(str);
- そもそもすべての数値(int型、double型など)は文字列に変換できるようになっている
- そうでなければ結果を画面に表示できない
String a = "$"; double b = 3.75; String str = a + b; System.out.println(str);
char a = '$'; double b = 3.75; String str = a + b; // Error
int x = 3 * 7; System.out.println("3*7=" + x);
int i = 3776; char c = '㍍'; System.out.println("富士山の高さは" + i + c);
double pi = 3.1415926534; String s1 = "π="; String s2 = s1 + pi; System.out.println(s2);
double pi = 3.1415926534; String s1 = "" + pi; System.out.println(s1);
char a = '$'; double b = 3.75; double c = a + b; System.out.println(c);
9.3. 文字列オブジェクトと操作
- オブジェクト(object)とは?
- オブジェクトとは操作の対象となる もの
- 文字列もオブジェクトである
- 文字列オブジェクトに対して操作する(operate)ための方法(method)がある ー 加算(concatenate)も操作(method)の一つ
情報をオブジェクトとして取り扱うことがオブジェクト指向言語の特徴
- 文字列の加算(連結)をよりオブジェクト指向らしく表現すると次の通り。
String s1 = "abc"; String s2 = "def"; String s3 = s1.concat(s2); // s1 + s2 と同じ意味 // String s3 = s2.concat(s1); // 結果が逆になる System.out.println(s3);
- ドット表記(dot notitation)
object.method()
という表現でオブジェクトを操作できる- dotとはピリオド記号のこと
- 日本語の助詞「の」だと理解しておいて大体OK
- ドット表記以外に主に簡略化のための別の表記法もある
- 文字列を結合する「+演算子」も文字列に対する操作
- 引数(argument)
- オブジェクトを操作するために追加で必要な情報
object.method(arg1, arg2)
のように,操作に応じて必要な引数の数は異なる
10. 文字列の比較や長さ #10
10.1. 文字列オブジェクトの比較
- 文字列の内容が等しいことを調べる操作(equals)
- 基本型における
==
- 基本型における
String str1 = "ABC"; String str2 = "ABC"; System.out.println(str1.equals(str2));
equals
と==
の違い
String str1 = "あいうえお"; String str2 = "あいうえお"; String str3 = "あい"; str3 = str3 + "うえお"; System.out.println(str1 == str2); System.out.println(str1 == str3); System.out.println(str1.equals(str2)); System.out.println(str1.equals(str3));
文字列の比較にはequals()を使うこと!
10.2. 文字列オブジェクトの長さに関連する操作
- 文字列の長さを求める操作(length)
String str = "あいうえお"; System.out.println(str.length()); str = "ふるいけやかわずとびこむみずのおと"; System.out.println(str.length());
- 文字列から文字を取り出す操作(charAt)
- 先頭の文字は0番目と数える
String str = "あいうえお"; char ch = str.charAt(0); // char型 System.out.println(ch);
- 文字列の長さを超えて取り出すことはできない
String str = "あいうえお"; char ch = str.charAt(5); System.out.println(ch);
- 文字列から部分文字列を取り出す操作(substring)
String str = "あいうえお"; String sub = str.substring(1); System.out.println(sub);
- 任意の範囲
String str = "0123456789"; String sub = str.substring(3, 6); System.out.println(sub);
10.3. 文字列オブジェクトの様々な操作
- 様々な文字列の操作
- その他の操作
10.4. ここまでで作れるプログラムの例(参考)
class Main { public static void main(String[] args) { double taijuu = 80.0; double shinchou = 1.7; double bmi = taijuu / (shinchou * shinchou); System.out.println("あなたのBMIは" + bmi + "です"); System.out.println("普通体重? = " + ((18.5 <= bmi) && (bmi < 25.0))); } }
11. 配列型(Array) #11
11.1. 配列とは?
- 配列 とは?
- 同じ型の値を複数個まとめて取り扱うための仕組み
- 配列にある一つ一つの値を 要素(element) という
- 配列の長さ
- 配列には 長さ(length) がある
- 長さは0以上、メモリの限界まで
- 配列の要素
- 配列の要素には0番から配列の長さ-1番までの 番号(index) が振られる
- 番号を用いて要素に代入や参照できる
11.2. 配列変数の宣言
- 型名に
[]
をつける
int[] iArray; double[] dArray; char[] chArray; String[] strArray;
11.3. 配列変数の初期化(配列の直値)
- 配列変数の初期化
- 配列の要素に代入すること
- 配列の直値表現
- 同じ型の直値を「{」「}」で括り,「,」で区切って並べる
- 宣言と同時に初期化する際、配列の直値表現で初期化できる。
int[] iArray = {0, 1, 2, 3}; double[] dArray = {1, 1.414, 1.732, 2, 2.236}; char[] chArray = {'あ','い','う', 'A', 'B'}; String[] strArray = {"こんにちは", "さようなら", "ありがとう", "おやすみ"};
11.4. 配列の要素を参照する
- 配列変数に番号をつけて参照できる
int[] iArray = {0, 1, 2, 3}; System.out.println(iArray[0]); System.out.println(iArray[3]);
String[] strArray = {"こんにちは", "さようなら", "ありがとう", "おやすみ"}; System.out.println(strArray[2]); System.out.println(strArray[3]);
- 番号が長さを超えた場合
- 実行時例外 になる
double[] dArray = {1, 1.414, 1.732, 2, 2.236}; System.out.println(dArray[5]); // 実行時に例外 System.out.println(dArray[-1]); // 実行時に例外
11.5. 配列の要素に代入する
- 代入もできる
char[] chArray = {'あ','い','う', 'A', 'B'}; chArray[1] = 'わ'; System.out.println(chArray[1]);
11.6. 変数を用いた要素の指定
- 番号に整数型の変数を用いることができる
double[] dArray = {1, 1.414, 1.732, 2, 2.236}; int i = 0; System.out.println(dArray[i]); i++; System.out.println(dArray[i]);
変数で要素を指定して代入・参照できることこそ配列の重要な利点。 後に「繰り返し」と組み合わせる。
11.7. 多次元配列
- 2次元以上の配列を作ることができる
- 225次元までらしい
int[][] image = {{1,0,1}, {0,1,0}, {1,0,1}}; System.out.println(image[0][2]); System.out.println(image[1][1]);
11.8. 配列の長さ(length)
- ドット表記で配列の長さを求めることができる
int[] array = {2, 3, 5, 7, 11, 13, 17, 19}; System.out.println(array.length);
- 二次元配列の長さ
int[][] image = {{1,0,1,0}, {0,1,0,1}, {1,0,1,1}}; System.out.println(image.length); System.out.println(image[0].length);
文字列の場合、 length()
であるのに対して、配列は length
。
あきらかに紛らわしい。どうしてそうなったかは知らぬ。
Java言語を開発したデザイナーが決めたことである。
11.9. 配列を文字列に変換する(Arrays.toString())
- 配列はオブジェクト?
- オブジェクトである
- しかしながら、配列そのものをオブジェクトとしてドット表記で メソッドを呼び出すことはあまりない
- Arraysオブジェクト
- 配列を操作するためのオブジェクト
- 配列を文字列に変換する
int[] array = {2, 3, 5, 7, 11, 13, 17, 19}; System.out.println(Arrays.toString(array));
- 要素が変更されたことを確認
int[] array = {2, 3, 5, 7, 11, 13, 17, 19}; array[3] = 0; System.out.println(Arrays.toString(array));
- 多次元配列の場合
int[][] image = {{1,0,1,0}, {0,1,0,1}, {1,0,1,1}}; System.out.println(Arrays.deepToString(image));
12. 構造化プログラミング1
12.1. プログラムの制御構造
12.1.1. 条件分岐とジャンプ
- 条件分岐
- ある条件を満たすかどうかでプログラムの制御の流れを変更すること
- ジャンプ
- 条件が成立したとき、プログラムの一部を飛ばす
- スパゲッティプログラム
- ジャンプをむやみに使うことで、プログラムが読みづらくなる
12.1.2. 構造化プログラミング(Structured programming)
- ジャンプを使わず、「順次、選択、反復、サブルーチンがあればどんなプログラムでも書けますよ」
- このプログラミング手法の普及に貢献したのは、1968年の計算機科学者エドガー・ダイクストラ(Edsger Wybe Dijkstra)によるACM機関紙への投書「Go To Statement Considered Harmful」と言われている
- Go To Statementとは?
- プログラムの任意の位置に移動する機能(ジャンプ)
- これらに加え、現代的なプログラミング言語には例外処理の機構がある
- 用途を限定した Go To Statement である
12.1.3. 構造化プログラミングの制御構文
- 順次(sequence)
- ステートメントまたはブロックステートメントを順々に処理する
- 選択(selection)
- 条件式の結果に従って次に実行するステートメントまたはブロックを選択してフロー分岐する
- 反復(repetition)
- 特定の状態の間、ステートメントまたはブロック内を繰り返す
- 状態の確認は反復起点時または反復終点時の二通りある
- サブルーチン(subroutine)
- これをコールした次のステートメントに復帰(return)する事を前提にして対象ブロックの起点にジャンプする
- 終点に達すると自動的に復帰する他、任意の途中位置でも復帰できる
- 例外処理(Exception Handling)
- プログラムの過程で計算の実行が不可能になった場合、例外が発生したと扱い、例外処理のための記述にジャンプする
12.2. 順次(sequence)とは?
- 順次構造で文をつなげる
- 文は必ず上から下へ、順番に次々実行される
- Javaによる表現
- 各々の文は「;」で区切る
int a = 3; int b = a * 4; System.out.println(b);
- 複合文(ブロック)
- 文が複数個集まり、複合文という一つの文になる
- Block AとBlock Bを順次でつなぐ
- Javaによる表現
{ System.out.println("Block A"); } { System.out.println("Block B"); }
12.3. 選択(selection)とは?
12.3.1. 条件分岐
- 選択は「条件分岐(conditional branch)」とも呼ばれる(こちらが一般的)
- ある条件を満たすかどうかで文を実行するか、あるいは、どの文を選択して実行するかを判断する
- 条件は値が真偽値となる 式
- 論理演算・比較演算 参照
12.3.2. 二股に分岐する選択
- 変数flagがboolean型であるとき
- flagが真(true)ならばStatementを実行する
- falseならば実行しない
- 条件が成立したときに実行するブロックをthenブロックという
- Java言語での表現
- if文を用いる
System.out.println("start"); if(true) { System.out.println("true"); } System.out.println("end");
- 条件にboolean型の変数を用いる場合
boolean flag = true; System.out.println("start"); if(flag) { System.out.println("true"); } System.out.println("end");
- 条件に論理演算を用いる場合
System.out.println("start"); if(false || true) { System.out.println("true"); } System.out.println("end");
- 条件に比較演算を用いる場合
System.out.println("start"); if(0 < 1) { System.out.println("true"); } System.out.println("end");
12.3.3. elseブロックのある選択
- flagが偽(false)のときに実行する文がある場合
- 二股に分岐する
- 条件が不成立のときに実行するブロックをelseブロックと言う。
- Java言語での表現
boolean flag = true; System.out.println("start"); if(flag) { System.out.println("then block"); } else { System.out.println("else block"); } System.out.println("end");
- 多段階に分岐する場合
- if文のthenブロックやelseブロックに更にif文を埋め込む
- Java言語での表現
boolean cond1 = false; boolean cond2 = false; boolean cond3 = true; System.out.println("start"); if(cond1) { // Block A System.out.println("cond1=true"); } else { System.out.println("cond1=false"); if(cond2) { // Block B System.out.println("cond2=true"); } else { System.out.println("cond2=false"); if(cond3) { // Block C System.out.println("cond3=true"); } else { // Block D System.out.println("cond3=false"); } } } System.out.println("end");
else if
- ブロックの中に更にブロックをどんどん埋め込んでいくと、ネストが深くなる
- 全体の構造がわかりにくい
else if
により、これを避ける
- Java言語での表現
boolean cond1 = true; boolean cond2 = true; boolean cond3 = true; System.out.println("start"); if(cond1) { // Block A System.out.println("cond1=true"); } else if(cond2) { // Block B System.out.println("cond2=true"); } else if(cond3) { // Block C System.out.println("cond3=true"); } else { // Block D System.out.println("other"); } System.out.println("end");
12.3.4. 3つ以上に分岐する場合(switch文)
if/else/else if
の他、switch
文もある
int i = 1; switch (i) { case 1: System.out.println("one"); break; case 2: System.out.println("two"); break; case 3: System.out.println("three"); break; default: System.out.println("default"); break; }
12.4. 反復(repetition)
12.4.1. 反復とは?
- 一般的には「繰り返し(loop)」と呼ぶ
- ある条件を満たしている間、同じ文を繰り返す
- 条件判定を文を実行する前に行う方法(前判定)と、文を実行した後に行う方法(後判定)がある
12.4.2. 反復の記述方法
- 前判定の反復
- 継続条件を反復の始まりで判定する
- 後判定の反復
- 継続条件を反復の終わりで判定する
- あまり使わない
12.4.3. Javaによる表現
- 無限反復(無限ループ)
- 継続条件が常にtrueなので、無限にブロックを繰り返す
- 後で説明する break 文で抜け出すことは可能
while (true) { System.out.println("Hello world"); }
- 継続条件がfalseの場合
- ブロックは実行されない
- elseブロックのないif文と同じ
while (false) { System.out.println("Hello world"); }
- 指定回数繰り返す方法
- 回数を数えるための変数(カウンタ)を初期化
- 継続条件でカウンタを判定する
- ブロックの最後でカウンタを更新する
int i = 0; // カウンタを初期化 while (i < 5) { // カウンタを判定 System.out.println("Hello world"); i ++; // カウンタを更新 }
- 初期値2から2づつ進ませる
- カウンタを画面に表示する
int i = 2; while (i <= 10) { System.out.println("i=" + i); i += 2; }
- マイナス方向にカウント
int i = -1; while (-20 < i) { System.out.println("i=" + i); i *= 2; }
13. 構造化プログラミング2 #12
13.1. 反復の続き
13.1.1. 反復を用いた配列の処理
- 配列のすべての要素を参照
- 継続条件は、カウンタが配列のlength未満
int[] array = {73, 92, 88, 81, 65}; int i = 0; while (i < array.length) { System.out.println(array[i]); i ++; }
- 文字列配列のすべての要素を表示
- 継続条件は、カウンタiが配列のlength未満
String[] array = {"はじめまして", "こんにちは", "さようなら", "ありがとう"}; int i = 0; while (i < array.length) { System.out.println(array[i]); i ++; }
- 配列の値を合計する
int[] array = {73, 92, 88, 81, 65}; int sum = 0; // 合計を格納する変数 int i = 0; while (i < array.length) { sum += array[i]; i ++; } System.out.println("sum=" + sum);
- 配列の値を平均する
int[] array = {73, 92, 88, 81, 65}; int sum = 0; // 合計を格納する変数 int i = 0; while (i < array.length) { sum += array[i]; i ++; } // 平均を計算する double average = (double) sum / array.length; System.out.println("average=" + average);
13.1.2. for文
- 前判定の反復
- カウンタの初期化
- 継続条件
- カウンタの更新
- for文はこれらをまとめて表現できる
String[] array = {"はじめまして", "こんにちは", "さようなら", "ありがとう"}; int i = 0; // カウンタの初期化 while (i < array.length) { // 継続条件 System.out.println(array[i]); i ++; // カウンタの更新 }
String[] array = {"はじめまして", "こんにちは", "さようなら", "ありがとう"}; for(int i = 0; i < array.length; i++) { // 初期化・継続条件・更新 System.out.println(array[i]); }
for文はwhile文を書きやすくするための糖衣構文(Syntax sugaro)である。 ただし、カウンタ変数の定義域はfor文のブロック内となる。
13.1.3. 後判定(repeat文)
- repeat文
- ブロックを必ず1回実行する
- 継続条件を判定し、継続する場合再度ブロックを実行
int i = 0; // i = 10とすると? while (i < 5) { System.out.println("こんにちは"); i ++; }
int i = 0; // i = 10とすると? do { System.out.println("こんにちは"); i ++; } while (i < 5);
- 前判定と後判定の使い分け
- よく使うのは前判定
- 後判定が有効なのはわりと特殊であるが、ここぞというときに使えると格好が良い
13.1.4. break文/continue文
- break文 ー 反復の途中で抜け出す
int[] array = {2, 3, -1, 5, 6}; int i = 0; while (i < array.length) { System.out.println(array[i]); if (array[i] == -1) { break; } i ++; }
- continue文
- それ以降のブロックの実行をしない
- for文と組み合わせることが多い
int[] array = {2, 3, -1, 5, 6}; for (int i = 0; i < array.length; i ++) { if (array[i] == -1) { continue; } System.out.println(array[i]); }
- while文で使うと、カウンタの変更をしないので注意
int[] array = {2, 3, -1, 5, 6}; int i = 0; while (i < array.length) { if (array[i] == -1) { i ++; // 必要 continue; } System.out.println(array[i]); i ++; }
14. 構造化プログラミング3 #13
14.1. 応用:サイコロを振り6が出るまで繰り返す
Math.random()
メソッド- 0.0以上1.0未満の乱数を返す
- サイコロの作り方
- 6をかけて1を足し、intに型変換すると1~6までの数が得られる
double ransuu = Math.random(); System.out.println("乱数=" + ransuu); int saikoro = ((int) (ransuu * 6)) + 1; System.out.println("サイコロ=" + saikoro);
int saikoro = 0; while (saikoro != 6) { double ransuu = Math.random(); System.out.println("乱数=" + ransuu); saikoro = ((int) (ransuu * 6)) + 1; System.out.println("サイコロ=" + saikoro); }
14.2. 例外(Exception Handling)
14.2.1. 例外とは?
- 正常に処理が行えなくなった場合、例外を発生させる
- 実行中のブロックを抜け、例外処理のブロックまでジャンプする
- 例外が発生する可能性のある処理を記述する場合
- tryブロックで囲む
- 例外が発生した場合に実行されるcatchブロックを記述
- 発生した例外の理由などを知るための変数が利用可能
14.2.2. 例外の発生のさせかた
- 例外を発生させる方法
throw new Exception()
boolean flag = false; try { System.out.println("開始"); if (flag) { System.out.println("ここで例外発生"); throw new Exception("テスト"); } System.out.println("正常に終了"); } catch(Exception e) { System.out.println("処理がうまくいきませんでした"); System.out.println("例外の理由:" + e.getMessage()); }
14.2.3. 例:計算結果が例外を発生させる場合
- 整数を0で除算した場合、計算不能
int a = 12; int b = 3; // b = 0 で例外発生 try { System.out.println("開始"); int x = a / b; System.out.println("a / b =" + x); System.out.println("正常に終了"); } catch(Exception e) { System.out.println("処理がうまくいきませんでした"); System.out.println("例外の理由:" + e.getMessage()); }
14.2.4. 例:参照型の変数がnull型の場合
- メソッドを呼び出すと例外発生
String str = "文字列"; // str = null で例外発生 try { System.out.println("開始"); System.out.println("str.length()=" + str.length()); System.out.println("正常に終了"); } catch(Exception e) { System.out.println("処理がうまくいきませんでした"); System.out.println("例外の理由:" + e.getMessage()); }
14.2.5. 配列の範囲を超えた場合
- 配列の添字が要素数を超えている
int[] array = {1 , 2, 3}; try { System.out.println("開始"); System.out.println("array[0]=" + array[0]); // -1 や 3で例外発生 System.out.println("正常に終了"); } catch(Exception e) { System.out.println("処理がうまくいきませんでした"); System.out.println("例外の理由:" + e.getMessage()); }
14.2.6. 例外処理の省略
- 例外処理は省略できる場合とできない場合がある
- 全てのブロックに例外処理を記述するのは鬱陶しい
- 例外処理が省略できる場合
- 0での割り算
- 変数がnullである時のメソッド呼び出し
- 配列の範囲を超えた参照 など
- 必要な場合
- 例外が起こり得る可能性の高い、特定のメソッドを呼び出す場合
- ファイルやネットワークへのアクセス など
14.2.7. 実行時例外(Runtime Exception)の例(文字列型の場合)
- 文字列の長さを超えた場合
String str = "あいうえお"; System.out.println(str.charAt(6));
- オブジェクトがnullであった場合
String str = null; System.out.println(str.length()); // 実行できない
14.3. サブルーチン(subroutine)
14.3.1. サブルーチンとは?
- サブルーチンは、Javaではメソッド(method)と言う
- いままでもいくつかのメソッドを利用してきた
System.out.println()
- 文字列に対する
length()
等
- いままでもいくつかのメソッドを利用してきた
14.3.2. メソッドを作成する
- メソッドは自分で作成することもできる
- ブロックに名前を付ける
- ブロックを様々な場所から呼び出す
- メソッドを作成する場所
- class ブロックに作成する
- mainブロックではない!
- 実はmainブロックはメソッド
- 同じ内容を一つにまとめる
- 一度書いたものを再利用する
class Main { public static void main(String[] args) { System.out.println("ふるいけや かわずとびこむ みずのおと"); System.out.println(" それにつけても かねのほしさよ"); System.out.println("めにあおば やまほととぎず はつがつお"); System.out.println(" それにつけても かねのほしさよ"); System.out.println("しずかさや いわにしみこむ せみのこえ"); System.out.println(" それにつけても かねのほしさよ"); } }
- 下の句をメソッドにすると、再利用できる。
class Main { public static void main(String[] args) { System.out.println("ふるいけや かわずとびこむ みずのおと"); shimonoku(); // メソッドを呼び出す System.out.println("めにあおば やまほととぎず はつがつお"); shimonoku(); // メソッドを呼び出す System.out.println("しずかさや いわにしみこむ せみのこえ"); shimonoku(); // メソッドを呼び出す } static void shimonoku() { // メソッドのブロック System.out.println(" それにつけても かねのほしさよ"); } }
14.3.3. メソッドに引数(arguments)を渡す方法
- 次の例で同じ箇所を再利用したい
class Main { public static void main(String[] args) { System.out.println("佐藤さん、こんにちは。"); System.out.println("ごきげんいかがですか?"); System.out.println("田中さん、こんにちは。"); System.out.println("ごきげんいかがですか?"); System.out.println("鈴木さん、こんにちは。"); System.out.println("ごきげんいかがですか?"); } }
- 名前(名字)以外は同じ
- 同じものを一つにまとめたい
- 名前を変数にすればよい。
- 変数はブロック内に作るものとする
- 変数の定義域はブロック
- 参照:変数の名前空間(name space)
class Main { public static void main(String[] args) { { String name = "佐藤"; System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); } { String name = "田中"; System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); } { String name = "鈴木"; System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); } } }
- 引数の種類
- 実引数
- メソッドを呼び出すときの値
- 仮引数
- メソッドが受け取る値を代入する変数
- 実引数
- 実引数は自動的に仮引数に代入される
- ブロックを呼び出すとき、ブロックが使用する変数に自動的に代入される
class Main { public static void main(String[] args) { greeting("佐藤"); greeting("田中"); greeting("鈴木"); } static void greeting(String name) { System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); } }
- 引数はいくつでも作れる
- 実引数は値をカンマで区切る
- 仮引数は変数宣言をカンマで区切る
class Main { public static void main(String[] args) { greeting("佐藤", true); greeting("田中", false); greeting("鈴木", true); } static void greeting(String name, boolean flag) { System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); if (flag) { System.out.println(" こんど、遊びに行きましょう。"); } } }
14.3.4. メソッドを途中で抜ける
- メソッドのブロックから途中で抜けることができる
reutrn
文を使う
class Main { public static void main(String[] args) { greeting("佐藤", true); greeting("田中", false); greeting("鈴木", true); } static void greeting(String name, boolean flag) { System.out.println(name + "さん、こんにちは。"); System.out.println(" ごきげんいかがですか?"); if (!flag) { return; // メソッドのブロックから抜ける } System.out.println(" こんど、遊びに行きましょう。"); return; // 最後のreturnは省略可能 } }
14.3.5. メソッドの戻り値
- メソッドで計算した結果を受け取ることができる
- reutrn文に値を追加する
- メソッドに戻り値の型を指定する
- return文で戻す値の型
- 戻り値は1つのみ
- 引数は複数
- 戻り値には名前はない
class Main { public static void main(String[] args) { System.out.println("add(1, 3)=" + add(1, 3)); System.out.println("add(5, 12)=" + add(5, 12)); System.out.println("add(2, -7)=" + add(2, -7)); } static int add(int a, int b) { return a + b; } }
class Main { public static void main(String[] args) { System.out.println("bye(\"本田\")=" + bye("本田")); System.out.println("bye(\"松本\")=" + bye("松本")); System.out.println("bye(\"林\")=" + bye("林")); } static String bye(String name) { return name + "さん、ごきげんよう"; } }
14.3.6. メソッドのまとめ
- メソッドの構造(input-process-output)
- 入力:何らかの値を受け取る
- 処理:値を用いて計算する
- 出力:計算結果の値を引き渡す
- メソッドの定義
- 出力する値の型(無い場合、void)
- メソッドの名前(識別子)
- 入力する値の名前と型(0個以上の引数)
- メソッドからの復帰
- 任意の場所から復帰可能
- 復帰の際、戻り値の値を指定する
14.3.7. サンプルプログラム
15. 最終課題
15.1. 課題について
- Javaプログラミングに関するレポートを提出
- 提出先
- Googleクラスルーム
- 提出方法
- Googleドキュメントでレポートを作成する
- 学籍番号、氏名を記載すること
- 課題と問題の番号、及び解答を記載すること
15.2. 課題1
人間が計算機を作り、計算機科学を研究して発展させてきた背景には、人が手で計算することでは到底求められない数を正確に計算させたいという要求があった。
その代表的な数として円周率(π)がある。紀元前250頃、アルキメデスは幾何学的な計算により円周率は約3.14であることを求めた。時は流れ、18年初頭にマチンは100桁まで手計算で求めた。19世紀半ばシャンクスは707桁まで計算したが、死後、527桁より先の計算は間違いであることが判明した。
計算機を用いて最初に円周率が求められたのは1949年のことであった。ENIACという計算機を用いて円周率を求め2037桁計算した。計算にかかった時間は70時間ほどであったという。そして、2022年6月にグーグルは円周率を100兆桁まで求めたことを発表した。このように、計算機を用いると人間が手で行うことは不可能だと考えられる計算を行うことができる。
次のプログラムは「Leibniz」の公式により円周率を計算するプログラムである(ChatGPTが作成したものを改変)。現在、小数点1桁まで正しく計算できる。このプログラムをもとに、できるだけ多くの桁数を正確に求められるように改良しなさい。
なお、Java言語では予め、Math.PIという変数に円周率が代入されているので、これとの比較を行うことで、正しい桁数がわかる。
int terms = 100; double pi = 0.0; boolean positive = true; for (int i = 0; i < terms; i++) { int divisor = 2 * i + 1; if (positive) { pi += 1.0 / divisor; } else { pi -= 1.0 / divisor; } positive = !positive; } pi *= 4; System.out.println("Leibnizの公式 による円周率の近似値: " + pi); System.out.println("Math.PI による円周率の近似値: " + Math.PI);
問題
- (1) 改良したプログラムのURL(repl.it)
- (2) プログラムをどのように変更したか?
- (3) 求められた桁数は小数点以下何桁か?
- (4) 苦労した点・工夫した点
- (5) この課題の感想
15.3. 課題2
素数とは1とそれ自身の数以外では割り切れない整数である。小さい方から、2、3、5、7、13、17、19、23、29・・・と続く。全ての素数を導き出す公式は存在しないとされている。しかし、計算機で計算させることはできる。
ChatGPTに、100までの素数を求めるプログラムを作らせたところ、次のプログラムを得た(授業で習った範囲の知識に限定するために一部改変)。 また、計算にかかる時間をミリ秒で計測するためのコードを追加した(★で示した)。
このプログラムをもとに、できるだけ多くの素数を求めるように改良したい。
long startTime = System.currentTimeMillis(); // ★ int n = 100; boolean[] primes = new boolean[n + 1]; // 0〜nまでの配列を用意 for (int i = 2; i <= n; i++) { primes[i] = true; } for (int i = 2; i * i <= n; i++) { if (primes[i]) { for (int j = i * i; j <= n; j += i) { primes[j] = false; } } } long endTime = System.currentTimeMillis(); // ★ System.out.println("\n" + n + "までの素数を求める計算にかかった時間は" + (endTime - startTime) + "ミリ秒です。"); System.out.println("2 から " + n + " までの素数:"); for (int i = 2; i <= n; i++) { if (primes[i]) { System.out.print(i + " "); } }
問題
- (1) 改良したプログラムのURL(repl.it)
- (2) プログラムをどのように変更したか?
- (3) 求められた素数は何個か?
- (4) 苦労した点・工夫した点
- (5) この計算方法の名前は何か?
- (6) この課題の感想
15.4. 課題3
コンピュータを利用すると、とても大きな数や、とても小さな数を用いた様々な計算を行うことができる。特に天文学の分野ではそのような数を用いた計算が必須である。まさに、「天文学的な数」を計算させることが求められる。
さて、一週間は、日、月、火、水、木、金、土の7日間である。それぞれの曜日は太陽系の天体と対応しているが、それぞれ大きさも重さもまちまちである。
そこで、全ての曜日の長さが等しく24時間になっているのは不自然だとは考えられないか?それぞれの天体のデータを調べ、次の問題に答えよ。結果と、計算のために作製したプログラムを示せ(repl.itのURL)。
なお、一週間全体の長さは24×7=168時間のままで変わらないものとする。
問題
- (1) 各曜日の長さが各天体の「直径」に比例すると考えた時、曜日ごとの時間はどうなるか?
- (2) 各曜日の長さが各天体の「体積」に比例すると考えた時、曜日ごとの時間はどうなるか?
- (3) 各曜日の長さが各天体の「質量」に比例すると考えた時、曜日ごとの時間はどうなるか?
- (4) 苦労した点・工夫した点
- (5) この課題の感想。