Java学習ノート_140712（文字列、ラッパークラス、例外処理）

## 前回の復習

兼ねて練習問題クリア。全部まとめて解答。

```java:PracticeSample.java
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

public class JavaPracticeSample {
	public static void main(String[] args) {
		
		//1. Dateクラスを使って現在が何月かを表示。
		Date date = new Date();
		System.out.println(date.getMonth() + 1);

		//2. Calendarクラスを使って現在が何月かを表示。
		//Date.getMonth()は非推奨なので、Calendarクラスから下記のように呼び出す。
		Calendar cal = Calendar.getInstance();
		System.out.println(cal.get(Calendar.MONTH) + 1);
		
		//3. RandomクラスのnextBooleanメソッドを使って条件分岐処理を行う。
		//if(new Random().nextBoolean()){} みたいにも書ける。
		Random rand = new Random();
		boolean isLucky = rand.nextBoolean();
		if(isLucky){
			System.out.println("ラッキー");
		}else{
			System.out.println("アンラッキー");
		}
	}
}
```

# 文字列を扱う
## Stringクラスの利用

Stringクラスは実はchar配列をフィールドに持ったクラス。

以下は代表的なメソッド。

```java:StringSample.java

public class StringSample {

	public static void main(String[] args) {
		
		String str = new String("ABC");
		System.out.println(str);

		//こういう書き方もできる。
		char[] cc = new char[]{'A','B','C'};
		String str2 = new String(cc);
		System.out.println(str2);
		
		byte[] bb = {0x41, 0x42, 0x43};
		String str3 = new String(bb);
		System.out.println(str3);
		
		//charAt	指定した位置の文字を抜き出す
		System.out.println(str2.charAt(1));
		
		//length	文字列の長さを返す
		System.out.println(str2.length());
		
		String s1 = "abc";
		String s2 = "abc";
		String s3 = "ABC";
		
		//equals	文字列の比較（大文字小文字を区別）
		System.out.println(s1.equals(s2)); //true
		System.out.println(s1.equals(s3)); //false

		
		//equalsIgnoreCase	文字列の比較（大文字小文字を無視）
		System.out.println(s1.equalsIgnoreCase(s2)); //true
		System.out.println(s1.equalsIgnoreCase(s3)); //true
		
		//indexOf	指定文字列が含まれる位置を返す
		int pos = s1.indexOf("bc");
		System.out.println(pos);

		//含まれない場合は -1を返す
		int pos2 = s1.indexOf("d");
		System.out.println(pos2);
		
		String s4 = "ABCABCABC";
		
		//indexOf	複数発見された場合は、最初の文字の位置を返すが、
		//lastIndexOfは最後の位置を返す
		int pos3 = s4.lastIndexOf("C");
		System.out.println(pos3);
		
		//startsWith	始まりの文字列が指定文字列か、真偽値で返す
		//endWith		終わりの文字列が指定文字列か、真偽値で返す
		System.out.println(s4.startsWith("A"));
		System.out.println(s4.endsWith("D"));
		
		//substring		指定位置の文字列を返す、引数の取り方で、2通りある		
		String s5 = "abcdefg";
		System.out.println(s5.substring(5));
		System.out.println(s5.substring(2,3));
		
		//trim	前後の空白を削除する（単語間の空白は削除されない）
		String s6 = " hoge fuga hoge ";
		System.out.println(s6.trim());
		
		//replace	文字列の置換
		String s7 = "Hello, world!";
		System.out.println(s7.replace('o','0'));
		
		//replaceAll	正規表現で文字列の置換が行える
		//replaceFirst	正規表現で文字列の置換が行える（最初に一致したもののみ）
		//今回割愛
		
		//split	指定文字で区切り、配列で返す
		String s8 = "春はあけぼの、やうやう白くなりゆく山際、少しあかりて、紫だちたる雲の細くたなびきたる";
		String[] sArr = s8.split("、");
		//以前やった配列の要素に対するループ処理
		for(String s9 : sArr){
			System.out.println(s9);
		}
		
		//format	文字列を指定した書式でフォーマットして返す。printfと同じ形式が利用できる（未学習）
		//０フィルで5桁のフォーマットで表示
		String s10 = String.format("[%05d]", 12);
		System.out.println(s10);
		
	}

}
```

## Unicode

Javaでは文字を16bitのUnicodeで表現する。コンピュータの中では文字も数値として扱わせ、数値と文字を対応させたものが文字コード。Shift_JISやEUC、UTF-8などがある。`¥u3042¥u3044¥u3046`で「あいう」を表現する。

## 文字列の比較

equalsメソッドを使う。==での比較は、インスタンスが対象なため、インスタンスが異なる場合、文字列が同一でもfalseを返してしまう。そのため、Javaで文字列比較はequalsメソッドを使うこと。(newせずリテラルを代入する場合は、trueになる）

## 文字列の連結

文字列の連結は+で行うことが出来る。文字列ごStringインスタンスが生成されるため、
何度も連結する場合はStringBuilderクラスを利用する。

```java:StringBuilderSample.java
public class StringBuilderSample {

	public static void main(String[] args) {
		StringBuilder sb = new StringBuilder();
		
		sb.append("オラ");
		sb.append("悟空。");
		
		//prependメソッドないので、そういう処理はinsert(0,str);
		sb.insert(0, "オッス！");
		sb.append("いっちょやってみっか！");
		System.out.println(sb.toString());
	}

}
```
## 文字列と数字との変換

### 文字列→数字の変換

java.lang.IntegerクラスのparseIntメソッドを使う。

### 数字→文字列の変換

java.lang.IntegerクラスのtoStringメソッドを使う。

```java:ConvertSample.java
public class ConvertSample {

	public static void main(String[] args) {
		int i = 1000;
		double d = 1000;
		String s = "500";
		
		//文字列から数字への変換
		int sum = Integer.parseInt(s) + i;
		System.out.println("合計は" + sum + "です");

		//数字から文字列への変換
		String sentense  = s + Integer.toString(i);
		System.out.println(sentense);

		//数字から文字列への変換
		String sentense2  = s + String.valueOf(i);
		System.out.println(sentense2);
		
		//Doubleの場合はDouble#toString, Double#parseDouble を使う。
		double doubleSum = Double.parseDouble(s) + d;
		System.out.println(doubleSum);
		
		String sentense3 = s + Double.toString(d);
		System.out.println(sentense3);

		//String#valueOfはデータ型を各種引数に持つオーバーロード（多重定義）されたメソッド
		String sentense4 = s + String.valueOf(d);
		System.out.println(sentense4);
	}
}
```
## ラッパークラス

Integer,Doubleなどのクラスはintやdoubleなどの基本データ型を扱うためのクラスで、ラッパークラスと呼ばれる。

* 基本データ型をオブジェクトとして扱う
* 他の型と変換を行うユーティリティメソッドを提供する

種類 | 基本データ型 | ラッパークラス
----|-------------|-------------
論理 | boolean | Boolean
文字 | char | Character
整数 | byte | Byte
 | short | Short
 | int | Integer
 | long | Long
浮動小数 | float | Float
 | double | Double

```java:WrapperSample.java

public class WrapperSample {

	public static void main(String[] args) {
		
		/* 1. 基本データ型からラッパークラスへ変換 */
		//基本データ型からラッパークラスへの変換の例: コンストラクタ
		Integer n = new Integer(12);
		
		//staticなメソッドvalueOfを使って行うことも出来る
		Integer n2 = Integer.valueOf(12);

		/* 2. 文字列からラッパークラスへの変換 */
		//コンストラクタ, valueOfメソッドには引数に文字列を渡しても型キャストされる
		Integer n3 = new Integer("12");

		/* 3. ラッパークラスから基本データ型への変換 */		
		//ラッパークラスから基本データ型への変換はintValueメソッドなどのxxxValueメソッドを利用する。
		Integer n4 = new Integer(12);
		int num = n4.intValue();
				
		/* 4. ラッパークラスから文字列への変換 */
		Integer n5 = new Integer(12);
		String s = n5.toString();
		
		/* 5. 文字列から基本データ型への変換 */
		int num2 = Integer.parseInt("12");
	}
}
```

## ラッパークラスの定数

```java:ConstSample.java
		//ラッパークラスの定数：Integer型の定数の例
		int max = Integer.MAX_VALUE;
		int min = Integer.MIN_VALUE;
		System.out.println("MAX_VALUE : " + max + "\nMIN_VALUE : " + min );
		//MAX_VALUE : 2147483647
		//MIN_VALUE : -2147483648

```
## オートボクシング

Javaは基本データ型とラッパークラスの変換が代入時に自動で行われる。が例外が発生する可能性があるため、明示的に変換を行うほうが良いようだ。

```java
//以下は同義らしい
Integer n = new Integer(12);
int num = n.intValue();

Integer n = 12;
int num = n;
```

## 数字のフォーマット

以下のコードに内容をまとめた。

```java:FormatSample.java
import java.text.DecimalFormat;
import java.text.ParseException;

public class FormatSample {
	public static void main(String[] args){
		/* 数値から文字列へのフォーマット変換の例 */
		
		//コンストラクタ
		DecimalFormat df = new DecimalFormat("#.##");
		//
		String text = df.format(1.23456789);
		System.out.println(text);
		
		//#の場合、少ないと桁減る。多い場合は桁が増える。
		DecimalFormat df2 = new DecimalFormat("####");
		String text2 = df2.format(125);
		System.out.println(text2);
		
		//0の場合は0フィルしてくれる。多い場合は桁が増える。
		DecimalFormat df3 = new DecimalFormat("0000");
		String text3 = df3.format(125);
		System.out.println(text3);
		
		/* 文字列から数値へのフォーマット変換の例 */
		DecimalFormat df5 = new DecimalFormat("###,###");
        Number num2;
		try {
			num2 = df5.parse("120,000");
	        int n2 = num2.intValue();
	        System.out.println(n2);
		} catch (ParseException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
	}

}
```
parseExceptionの書き方でEclipseでエラーが何回かでたので、修正するとエラーがでなくなったのでOKとした。

## 問題

BMI値の計算ばっかりしてる。

```java:BMIPractice.java
import java.text.DecimalFormat;

public class BMIPractice {

	public static void main(String[] args) {
		double height = Double.parseDouble(args[0]) / 100;
		double weight = Double.parseDouble(args[1]);
		
		double bmi = weight / Math.pow(height, 2);
		
		DecimalFormat df = new DecimalFormat("#.##");
		String bmiStr = df.format(bmi);
		System.out.println("BMI値 : " + bmiStr);
		
	}
}
```

# 例外処理

```java:ThrowError.java

public class ThrowError {
	public static void main(String[] args) {
		int result = divOneTwo(args);
		System.out.println("result : " + result);
	}
	static int divOneTwo(String[] args){
		return Integer.parseInt(args[0]) / Integer.parseInt(args[1]);
	}
}
```

上記コードに引数を与えず実行すると、Eclipseのコンソールに例外が表示される。

```
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
	at ThrowError.divOneTwo(ThrowError.java:8)
	at ThrowError.main(ThrowError.java:4)

```
8行目、その呼び出し元である4行目、さらにその大元であるmainメソッドで、例外が発生することが表示されている。例外が発生すると、さかのぼって例外がスローされて、呼び出し元のメソッド（今回はmainメソッド）まで処理が戻される（例外発生以後のコードは実行されない）。`java.lang.ArrayIndexOutOfBoundsException: 0`は**スタックトレース**と呼ばれ、例外の発生場所や、原因を追跡するのに役立つ。

## javadocで例外クラスを見る

[ArrayIndexOutOfBoundsException (Java Platform SE 8 )](http://docs.oracle.com/javase/jp/8/api/java/lang/ArrayIndexOutOfBoundsException.html)

`java.lang.ArrayIndexOutOfBoundsException: 0`の末尾のゼロは、args配列の（？インデックス？）0番目にアクセスした時に起こったエラーということらしい。試しに引数を本来2つのところ、1つだけ与えて実行してみたところ、例外表示の末尾の数字は1になった。

## 標準ライブラリ内部からの例外スロー

引数を文字にした場合、

```
Exception in thread "main" java.lang.NumberFormatException: For input string: "a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at ThrowError.divOneTwo(ThrowError.java:8)
	at ThrowError.main(ThrowError.java:4)
```

というエラーがでる。javadocでInteger.parseIntの項目を確認。NumberFormattingExceptionが例外としてスローされる可能性がある、と書かれている。


## try ... catch文

これまでも使ってきているので、省略。コードで理解する。

```java:ExceptionSample.java

public class ExceptionSample {
	public static void main(String[] args) {
		try{
			int result = divOneTwo(args);
			System.out.println("result : " + result);			
		}
		catch(ArrayIndexOutOfBoundsException e){
			System.out.println("ArrayIndexOutOfBoundsExceptionをキャッチしました。");
		}
		catch(NumberFormatException e){
			System.out.println("NumberFormatExceptionをキャッチしました。");
		}
		catch(ArithmeticException e){
			System.out.println("ArithmeticExceptionをキャッチしました。");
		}
	}
	static int divOneTwo(String[] args){
		return Integer.parseInt(args[0]) / Integer.parseInt(args[1]);
	}
}

```

さらに、

```java
catch(Exception e){
//...
}
```
で（ほぼ）全ての例外がキャッチできる。

# その他

Eclipseのショートカット一覧とかみて試そうかなと思ったんだけど、まだそういう段階じゃなさそうなので、実行のショートカット（Cmd +  fn + f11)だけ試してみた。MacのSpotlightのショートカット、特別必要ない気がしたのでオフにした。