5月29日

テスト駆動開発で自動販売機を作る

例題はこちら⇒ TDDBC大阪

売上高を取得できるようにする

VendingMachineTest.java

	@Test
	public void testSale() {
		VendingMachine vm = new VendingMachine();
		int sale = vm.getSale();
		assertThat(sale, is(0));
		vm.throwInto(500);
		vm.purchace();
		sale = vm.getSale();
		assertThat(sale, is(120));
	}

売上高をインスタンス変数で保持する。
VendingMachine.java

public class VendingMachine {
	private int total = 0;
	private int stock = 5;
	private int sale = 0;

購入操作をしたときに売上高を増やし、そのインスタンス変数の値を返すようにする。
VendingMachine.java

	public Output purchace() {
		if (!isPurchacable()) {
			return new Output(0, 0);
		}
		total -= getJuicePrice();
		int change = total;
		total -= change;
		stock--;
		sale += getJuicePrice();
		return new Output(1, change);
	}

	public int getSale() {
		return sale;
	}

釣り銭を管理する

初期状態では、10円、50円、100円、500円の硬貨が、各10枚ずつ用意されている。

VendingMachineTest.java

	@Test
	public void testChangeStock() {
		VendingMachine vm = new VendingMachine();
		int s10 = vm.get10YenStock();
		assertThat(s10, is(10));
		int s50 = vm.get50YenStock();
		assertThat(s50, is(10));
		int s100 = vm.get100YenStock();
		assertThat(s100, is(10));
		int s500 = vm.get500YenStock();
		assertThat(s500, is(10));
	}

このテストにパスするコードを書く。
VendingMachine.java

	public int get10YenStock() {
		return 10;
	}

	public int get50YenStock() {
		return 10;
	}

	public int get100YenStock() {
		return 10;
	}

	public int get500YenStock() {
		return 10;
	}

150円を投入してジュースを買ったら、10円の釣り銭ストックが減る。
VendingMachineTest.java

	@Test
	public void testChangeStock() {
		VendingMachine vm = new VendingMachine();
		int s10 = vm.get10YenStock();
		assertThat(s10, is(10));
		int s50 = vm.get50YenStock();
		assertThat(s50, is(10));
		int s100 = vm.get100YenStock();
		assertThat(s100, is(10));
		int s500 = vm.get500YenStock();
		assertThat(s500, is(10));
		vm.throwInto(100);
		vm.throwInto(50);
		Output o = vm.purchace();
		s10 = vm.get10YenStock();
		assertThat(s10, is(7));
	}

購入するところで釣り銭のストックを減らす。
1回の購入なら残り7になるので、Fakeコードで実装する。

VendingMachine.java

	public Output purchace() {
		if (!isPurchacable()) {
			return new Output(0, 0);
		}
		total -= getJuicePrice();
		int change = total;
		decreaseStock(change);
		total -= change;
		stock--;
		sale += getJuicePrice();
		return new Output(1, change);
	}

	private void decreaseStock(int change) {
		stock10yen = 7;
	}

テストに2回目の購入を追加して、Fakeコードではテストにパスしないようにする。
VendingMachineTest.java

	@Test
	public void testChangeStock2() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(100);
		vm.throwInto(50);
		Output o = vm.purchace();
		assertThat(o.getJuiceCount(), is(1));
		assertThat(o.getChange(), is(30));
		int s10 = vm.get10YenStock();
		assertThat(s10, is(7));

		vm.throwInto(100);
		vm.throwInto(50);
		vm.purchace();
		s10 = vm.get10YenStock();
		assertThat(s10, is(4));
	}

お釣りに出す枚数だけ減らすように実装を修正する。
VendingMachine.java

	private void decreaseStock(int change) {
		stock10yen -= change / 10;
	}

200円を入れて購入したときのテストを用意する。
VendingMachineTest.java

	@Test
	public void testChangeStock3() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(100);
		vm.throwInto(100);
		vm.purchace();
		int s10 = vm.get10YenStock();
		assertThat(s10, is(7));
		int s50 = vm.get50YenStock();
		assertThat(s50, is(9));
	}

200円のテストにパスするコードを書く。
VendingMachine.java

	private void decreaseStock(int change) {
		if (change >= 50) {
			change -= 50;
			stock50yen--;
		}
		stock10yen -= change / 10;
	}

500円を入れて購入したときのテストを用意する。
VendingMachineTest.java

	@Test
	public void testChangeStock4() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(500);
		vm.purchace();
		int s10 = vm.get10YenStock();
		assertThat(s10, is(7));
		int s50 = vm.get50YenStock();
		assertThat(s50, is(9));
		int s100 = vm.get100YenStock();
		assertThat(s100, is(7));
	}

500円のテストにパスするコードを書く。
VendingMachine.java

	private void decreaseStock(int change) {
		if (change >= 100) {
			int c = change / 100;
			change -= c * 100;
			stock100yen -= c;
		}
		if (change >= 50) {
			change -= 50;
			stock50yen--;
		}
		stock10yen -= change / 10;
	}

1000円を入れて購入したときのテストを用意する。
VendingMachineTest.java

	@Test
	public void testChangeStock5() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(1000);
		vm.purchace();
		int s10 = vm.get10YenStock();
		assertThat(s10, is(7));
		int s50 = vm.get50YenStock();
		assertThat(s50, is(9));
		int s100 = vm.get100YenStock();
		assertThat(s100, is(7));
		int s500 = vm.get500YenStock();
		assertThat(s500, is(9));
	}

1000円のテストにパスするコードを書く。
VendingMachine.java

	private void decreaseStock(int change) {
		if (change >= 500) {
			change -= 500;
			stock500yen--;
		}
		if (change >= 100) {
			int c = change / 100;
			change -= c * 100;
			stock100yen -= c;
		}
		if (change >= 50) {
			change -= 50;
			stock50yen--;
		}
		stock10yen -= change / 10;
	}

10円玉の釣り銭を使い果たすテストを用意する。

VendingMachineTest.java

	@Test
	public void testChangeStock6() {
		VendingMachine vm = new VendingMachine();
		for (int i = 0; i < 3; i++) {
			vm.throwInto(100);
			vm.throwInto(50);
			vm.purchace();
		}
		int s10 = vm.get10YenStock();
		assertThat(s10, is(1));
		vm.throwInto(100);
		vm.throwInto(50);
		Output o = vm.purchace();
		s10 = vm.get10YenStock();
		assertThat(s10, is(1));
		assertThat(o.getJuiceCount(), is(0));
		assertThat(o.getChange(), is(0));
		int total = vm.getTotal();
		assertThat(total, is(150));
	}

5月25日

自動販売機をTDDで実装する

例題
TDDBC大阪

購入できるかどうかを調べるために、isPurchacable() メソッドを追加する。

	@Test
	public void testIsPurchacable() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.isPurchacable();
		assertThat(b, is(false));
	}

Eclipseでメソッドを生成するとテストをパスするようになる。

	public boolean isPurchacable() {
		return false;
	}

500円を投入すると購入可能になるテストを追加する。

	@Test
	public void testIsPurchacable() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.isPurchacable();
		assertThat(b, is(false));
		vm.throwInto(500);
		b = vm.isPurchacable();
		assertThat(b, is(true));
	}

自動販売機の購入の動作を実装する

お金を入れてボタンを押すとジュースとおつりが出てくる。

それっぽいテストを書いてみる。
出てくるもの(ジュースとおつり)をまとめて Output クラスとしておく。
VendingMachineTest.java

	@Test
	public void testPurchace() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(100);
		vm.throwInto(10);
		vm.throwInto(10);
		Output o = vm.purchace();
		assertThat(j, is(1));
		assertThat(change, is(0));
	}

Output.java

public class Output {
	private int juiceCount;
	private int change;

	public Output(int juiceCount, int change) {
		this.juiceCount = juiceCount;
		this.change = change;
	}

	public int getJuiceCount() {
		return juiceCount;
	}

	public int getChange() {
		return change;
	}
}

ここまでのコードは以下のとおり。
VendingMachineTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class VendingMachineTest {

	@Test
	public void testThrowInto() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
		change = vm.throwInto(50);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(60));
	}

	@Test
	public void testThrowIntoNotAccept() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(1);
		assertThat(change, is(1));
		int total = vm.getTotal();
		assertThat(total, is(0));
		change = vm.throwInto(5);
		assertThat(change, is(5));
		change = vm.throwInto(2000);
		assertThat(change, is(2000));
		change = vm.throwInto(5000);
		assertThat(change, is(5000));
		change = vm.throwInto(10000);
		assertThat(change, is(10000));
	}

	@Test
	public void testThrowIntoRefund() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
		int refund = vm.refund();
		assertThat(refund, is(10));
		total = vm.getTotal();
		assertThat(total, is(0));
		change = vm.throwInto(100);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(100));
		change = vm.throwInto(500);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(600));
		refund = vm.refund();
		assertThat(refund, is(600));
	}

	@Test
	public void testGetJuice() {
		VendingMachine vm = new VendingMachine();
		String name = vm.getJuiceName();
		assertThat(name, is("コーラ"));
		int price = vm.getJuicePrice();
		assertThat(price, is(120));
		int stock = vm.getJuiceStock();
		assertThat(stock, is(5));
	}

	@Test
	public void testIsPurchacable() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.isPurchacable();
		assertThat(b, is(false));
		vm.throwInto(500);
		b = vm.isPurchacable();
		assertThat(b, is(true));
	}

	@Test
	public void testPurchace() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(100);
		vm.throwInto(10);
		vm.throwInto(10);
		Output o = vm.purchace();
		assertThat(o.getJuiceCount(), is(1));
		assertThat(o.getChange(), is(0));
		int total = vm.getTotal();
		assertThat(total, is(0));
	}
}

VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		if (yen == 1) return 1;
		if (yen == 5) return 5;
		if (yen == 2000) return 2000;
		if (yen == 5000) return 5000;
		if (yen == 10000) return 10000;
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}

	public int refund() {
		int refund = total;
		total = 0;
		return refund;
	}

	public String getJuiceName() {
		return "コーラ";
	}

	public int getJuicePrice() {
		return 120;
	}

	public int getJuiceStock() {
		return 5;
	}

	public boolean isPurchacable() {
		if (getJuiceStock() == 0) return false;
		return total >= getJuicePrice();
	}

	public Output purchace() {
		return new Output(1, 0);
	}
}

Juice.java


public class Juice {
	private String name;
	private int price;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
}

500円を投入して購入する。

VendingMachineTest.java

	@Test
	public void testPurchace500() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(500);
		Output o = vm.purchace();
		assertThat(o.getJuiceCount(), is(1));
		assertThat(o.getChange(), is(380));
		int total = vm.getTotal();
		assertThat(total, is(0));
	}

1000円を投入して購入する。

VendingMachineTest.java

	@Test
	public void testPurchace1000() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(1000);
		Output o = vm.purchace();
		assertThat(o.getJuiceCount(), is(1));
		assertThat(o.getChange(), is(880));
		int total = vm.getTotal();
		assertThat(total, is(0));
	}

在庫切れを実装する。
500円を投入して購入する。

VendingMachineTest.java

	@Test
	public void testPurchace500() {
		VendingMachine vm = new VendingMachine();
		vm.throwInto(1000);
		Output o = vm.purchace();
		assertThat(o.getJuiceCount(), is(1));
		assertThat(o.getChange(), is(880));
		int stock = vm.getJuiceStock();
		assertThat(stock, is(4));
		for (int i = 0; i < 4; i++) {
			vm.throwInto(500);
			o = vm.purchace();
		}
		stock = vm.getJuiceStock();
		assertThat(stock, is(0));
		vm.throwInto(500);
		o = vm.purchace();
		assertThat(o.getJuiceCount(), is(0));
		assertThat(o.getChange(), is(0));
		int total = vm.getTotal();
		assertThat(total, is(500));
	}

売上高を確認できるようにする。

VendingMachineTest.java

	@Test
	public void testSale() {
		VendingMachine vm = new VendingMachine();
		int sale = vm.getSale();
		assertThat(sale, is(0));
		vm.throwInto(500);
		vm.purchace();
		sale = vm.getSale();
		assertThat(sale, is(120));
	}

5月22日

TDD(テスト駆動開発)

JUnitを使ったTDDの練習。

FizzBuzz

FizzBuzzをTDDで作ってみる。

最初にテストコードを書く。
FizzBuzzTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class FizzBuzzTest {

	@Test
	public void testSay1() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(1);
		assertThat(s, is("1"));
	}
}

そのテストコードをパスする最小限の実装をする。
FizzBuzz.java

public class FizzBuzz {
	public String say(int i) {
		return "1";
	}
}

テストコードを追加する。
FizzBuzzTest.java

	@Test
	public void testSay2() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(2);
		assertThat(s, is("2"));
	}

そのテストコードをパスする最小限の実装をする。
FizzBuzz.java

public class FizzBuzz {
	public String say(int i) {
		if (i == 2) return "2";
		return "1";
	}
}

テストコードを追加する。
FizzBuzzTest.java

	@Test
	public void testSay3() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(3);
		assertThat(s, is("Fizz"));
	}

テストコードを追加→テストにパスするように実装 を繰り返す。

そのテストコードをパスする最小限の実装をする。
FizzBuzz.java

public class FizzBuzz {
	public String say(int i) {
		if (i == 3) return "Fizz";
		if (i == 2) return "2";
		return "1";
	}
}

テストコードを追加する。
FizzBuzzTest.java

	@Test
	public void testSay4() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(4);
		assertThat(s, is("4"));
	}

数字を返すところは共通化できるのでリファクタリングする。

FizzBuzz.java

public class FizzBuzz {
	public String say(int i) {
		if (i == 3) return "Fizz";
		return String.valueOf(i);
	}
}

テストの追加、実装、リファクタリングを繰り返す。
最終的にはこんな感じのテストコードになる。

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class FizzBuzzTest {

	@Test
	public void testSay1() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(1);
		assertThat(s, is("1"));
	}

	@Test
	public void testSay2() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(2);
		assertThat(s, is("2"));
	}

	@Test
	public void testSay3() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(3);
		assertThat(s, is("Fizz"));
	}

	@Test
	public void testSay4() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(4);
		assertThat(s, is("4"));
	}

	@Test
	public void testSay5() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(5);
		assertThat(s, is("Buzz"));
	}

	@Test
	public void testSay6() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(6);
		assertThat(s, is("Fizz"));
	}

	@Test
	public void testSay78() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(7);
		assertThat(s, is("7"));
		s = fb.say(8);
		assertThat(s, is("8"));
	}

	@Test
	public void testSay10() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(10);
		assertThat(s, is("Buzz"));
	}

	@Test
	public void testSay15() {
		FizzBuzz fb = new FizzBuzz();
		String s = fb.say(15);
		assertThat(s, is("Fizz Buzz"));
	}
}

すべてのテストにパスするようになれば完成。
FizzBuzz.java


public class FizzBuzz {
	public String say(int i) {
		if (i % 15 == 0) return "Fizz Buzz";
		if (i % 3 == 0) return "Fizz";
		if (i % 5 == 0) return "Buzz";
		return String.valueOf(i);
	}
}

世界のナベアツ

世界のナベアツをTDDで作ってみる。

最初にテストコードを書く。
NabeatsuTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class NabeatsuTest {

	@Test
	public void testSay1() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(1);
		assertThat(s, is("1"));
	}
}

そのテストコードをパスする最小限の実装をする。
Nabeatsu.java

public class Nabeatsu{
	public String say(int i) {
		return "1";
	}
}

FizzBuzzと同様にテストコードを追加する。

NabeatsuTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class NabeatsuTest {

	@Test
	public void testSay() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(1);
		assertThat(s, is("1"));
		s = fb.say(2);
		assertThat(s, is("2"));
	}

	@Test
	public void testSay3() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(3);
		assertThat(s, is("さぁーん"));
	}
}

テストにパスするコードを書く。
Nabeatsu.java


public class Nabeatsu {
	public String say(int i) {
		if (i == 3) return "さぁーん";
		return String.valueOf(i);
	}
}

最終的なテストコードはこんな感じ。

NabeatsuTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class NabeatsuTest {

	@Test
	public void testSay() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(1);
		assertThat(s, is("1"));
		s = fb.say(2);
		assertThat(s, is("2"));
	}

	@Test
	public void testSay3() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(3);
		assertThat(s, is("さぁーん"));
	}

	@Test
	public void testSay6() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(6);
		assertThat(s, is("さぁーん"));
	}

	@Test
	public void testSay13() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(13);
		assertThat(s, is("さぁーん"));
	}

	@Test
	public void testSay23() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(23);
		assertThat(s, is("さぁーん"));
	}

	@Test
	public void testSay31() {
		Nabeatsu fb = new Nabeatsu();
		String s = fb.say(31);
		assertThat(s, is("さぁーん"));
	}
}

すべてのテストにパスするコード。
Nabeatsu.java


public class Nabeatsu {
	public String say(int i) {
		String s = String.valueOf(i);
		if (s.contains("3")) return "さぁーん";
		if (i % 3 == 0) return "さぁーん";
		return String.valueOf(i);
	}
}

自動販売機を作る

TDDBCの例題で自動販売機があったので、この例題でTDDしてみる。
http://devtesting.jp/tddbc/?TDDBC%E5%A4%A7%E9%98%AA

まずは自動販売機のクラスを作る。
VendingMachine.java

public class VendingMachine {
}

お金を投入するメソッドを追加する。戻り値はお釣りの金額を返す。
VendingMachine.java

public class VendingMachine {
	public int throwInto(int yen) {
		return 0;
	}
}

テストコードを追加する。
VendingMachineTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class VendingMachineTest {

	@Test
	public void testThrowInto() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
	}
}

テストにパスしたので、さらにテストコードを追加。
投入済みの金額を取得する getTotal() メソッドのテストを追加。
VendingMachineTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class VendingMachineTest {

	@Test
	public void testThrowInto() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
	}
}

VendingMachine.java


public class VendingMachine {
	public int throwInto(int yen) {
		return 0;
	}

	public int getTotal() {
		return 0; // 0 → 10 にすればテストにパスする。
	}
}

さらにテストコードを追加。
お金を連続投入する。

VendingMachineTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class VendingMachineTest {

	@Test
	public void testThrowInto() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
		change = vm.throwInto(50);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(60));
	}
}

連続投入したら投入済みの金額が合計されるようにする。
VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}
}

受け入れないお金(1円・5円・1000円以外のお札)は、そのまま返却するテストを追加。
VendingMachineTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class VendingMachineTest {

	@Test
	public void testThrowInto() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
		change = vm.throwInto(50);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(60));
	}

	@Test
	public void testThrowIntoNotAccept() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(1);
		assertThat(change, is(1));
		int total = vm.getTotal();
		assertThat(total, is(0));
		change = vm.throwInto(5);
		assertThat(change, is(5));
		change = vm.throwInto(2000);
		assertThat(change, is(2000));
		change = vm.throwInto(5000);
		assertThat(change, is(5000));
		change = vm.throwInto(10000);
		assertThat(change, is(10000));
	}
}

テストにパスするように実装を追加する。
VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		if (yen == 1) return 1;
		if (yen == 5) return 5;
		if (yen == 2000) return 2000;
		if (yen == 5000) return 5000;
		if (yen == 10000) return 10000;
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}
}

返却ボタンを実装する。メソッド名を refund() とする。
まずはテストコードを書く。
VendingMachineTest.java

	@Test
	public void testThrowIntoRefund() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(0));
		int refund = vm.refund();
		assertThat(refund, is(10));
	}

refund() メソッドを追加する。
VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		if (yen == 1) return 1;
		if (yen == 5) return 5;
		if (yen == 2000) return 2000;
		if (yen == 5000) return 5000;
		if (yen == 10000) return 10000;
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}

	public int refund() {
		return 0; // 0 → 10 に修正すればテストにパスする
	}
}

返却のテストを追加する。
VendingMachineTest.java

	@Test
	public void testThrowIntoRefund() {
		VendingMachine vm = new VendingMachine();
		int change = vm.throwInto(10);
		assertThat(change, is(0));
		int total = vm.getTotal();
		assertThat(total, is(10));
		int refund = vm.refund();
		assertThat(refund, is(10));
		total = vm.getTotal();
		assertThat(total, is(0));
		change = vm.throwInto(100);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(100));
		change = vm.throwInto(500);
		assertThat(change, is(0));
		total = vm.getTotal();
		assertThat(total, is(600));
		refund = vm.refund();
		assertThat(refund, is(600));
	}

テストにパスするように実装を修正する。
VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		if (yen == 1) return 1;
		if (yen == 5) return 5;
		if (yen == 2000) return 2000;
		if (yen == 5000) return 5000;
		if (yen == 10000) return 10000;
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}

	public int refund() {
		int refund = total;
		total = 0;
		return refund;
	}
}

ジュースの管理をできるようにする。
ジュースの名前と値段と在庫数を取得できるようにする。
VendingMachineTest.java

	@Test
	public void testGetJuice() {
		VendingMachine vm = new VendingMachine();
		String name = vm.getJuiceName();
		assertThat(name, is("コーラ"));
		int price = vm.getJuicePrice();
		assertThat(price, is(120));
		int stock = vm.getJuiceStock();
		assertThat(stock, is(5));
	}

テストにパスするコードを書く。
VendingMachine.java


public class VendingMachine {
	private int total;

	public int throwInto(int yen) {
		if (yen == 1) return 1;
		if (yen == 5) return 5;
		if (yen == 2000) return 2000;
		if (yen == 5000) return 5000;
		if (yen == 10000) return 10000;
		total += yen;
		return 0;
	}

	public int getTotal() {
		return total;
	}

	public int refund() {
		int refund = total;
		total = 0;
		return refund;
	}

	public String getJuiceName() {
		return "コーラ";
	}

	public int getJuicePrice() {
		return 120;
	}

	public int getJuiceStock() {
		return 5;
	}
}

5月18日

前回来てなかった人

テキストの以下のサンプルを入力して実行してみよう!

  • WriterSample2
  • ReaderSample
  • FileCopy
  • CloseSample
  • DownloadSample
  • FileSample

Java7から自動でcloseしてくれる機能が追加された。
try-with-resources文を使うと自動的にcloseしてくれる。
自動でcloseしてくれるオブジェクトは、AutoClosableインタフェースを実装しているクラス。
以下のコードを入力して、CloseSampleと比較してみよう!

CloseSample2.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
public class CloseSample2 {
 
    public static void main(String[] args) throws IOException {
        String src = &quot;hoge.txt&quot;;
        String dest = &quot;hoge2.txt&quot;;
        copy(dest, src);
    }
 
    public static void copy(String dest, String src) throws IOException {
        try (InputStream in = new FileInputStream(src);
             OutputStream out = new FileOutputStream(dest)) {
            int len;
            byte[] b = new byte[1024];
            while (true) {
                len = in.read(b);
                if (len &lt; 0) break;
                out.write(b, 0, len);
            }
        }
    }
}

前回来ていた人

Comparatorを実装して、ファイルを日付順とサイズ順でソートできるようにしてみよう!

Dir.java

import java.io.File;
import java.util.Arrays;

public class Dir {

	public static void main(String[] args) {
		String path;
		String option = null;
		if (args.length == 0) {
			path = &quot;.&quot;;
		} else {
			path = args[0];
			option = getOption(args);
		}
		File file = new File(path);
		dir(file, option);
	}

	private static String getOption(String[] args) {
		for (String s : args) {
			if (s.startsWith(&quot;/&quot;)) {
				return s;
			}
		}
		return null;
	}

	static SimpleDateFormat formatter = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);

	private static void dir(File parent, String option) {
		System.out.println(&quot;option=&quot; + option);
		File[] children = parent.listFiles();
		if (children != null) {
			if (option == null) {
				// ソートなし
			} else
			if (option.equals(&quot;/ON&quot;)) {
				// 名前順
				Arrays.sort(children, new FileNameComparator());
			} else
			if (option.equals(&quot;/OD&quot;)) {
				// 日付順
				Arrays.sort(children, new FileDateComparator());
			} else
			if (option.equals(&quot;/OS&quot;)) {
				// サイズ順
				Arrays.sort(children, new FileSizeComparator());
			}
			for (int i = 0; i &lt; children.length; i++) {
				File file = children[i];
				String d = formatter.format(file.lastModified());
				System.out.println(file.getName() + &quot;\t&quot; + file.length() + &quot;\t&quot; + d);
			}
		}
	}
}

FileNameComparator.java

import java.io.File;
import java.util.Comparator;

public class FileNameComparator implements Comparator&lt;File&gt; {
	@Override
	public int compare(File o1, File o2) {
		String n1 = o1.getName();
		String n2 = o2.getName();
		return -n1.compareTo(n2); // マイナスをつけて逆順にしている
	}
}

FileDateComparator.java

import java.io.File;
import java.util.Comparator;

public class FileDateComparator implements Comparator&lt;File&gt; {
	@Override
	public int compare(File o1, File o2) {
		long l1 = o1.lastModified();
		long l2 = o2.lastModified();
		if (l1 &lt; l2) return -1;
		if (l2 &lt; l1) return 1;
		return 0;
	}
}

コマンドプロンプトでの実行

作業ディレクトリに移動する。
現在は、c24 プロジェクトでプログラムを作成しているので、c24 のフォルダに移動する。

&gt; cd \All-in-One-Eclipse4.4\workspace\c24

java コマンドを実行して Dir プログラムを起動する。

&gt; java -cp bin Dir src /OD

java : java コマンド
-cp : クラスパスを指定するオプション(クラスファイルがbinフォルダにあるため)
bin : クラスファイルがある bin フォルダを指定している
Dir : 起動するクラスファイルを指定
src : ファイルの内容を表示するフォルダを指定している
/OD : ソートのオプションを指定している

テスト駆動開発

FizzBuzz でテスト駆動開発の練習をする。

FizzBuzz.java


public class FizzBuzz {
	public String say(int i) {
		return null;
	}
}

FizzBuzzTest.java

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;


public class FizzBuzzTest {

	@Test
	public void testSay1() {
		FizzBuzz fb = new FizzBuzz(); // インスタンスを生成
		String s = fb.say(1); // say(1)を呼び出して結果を取得する
		assertThat(s, is("1")); // 結果が "1" かどうかを比較
	}
}

5月15日

24章 ストリームを使いこなす

Writerを使う

WriterSample.java

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class WriterSample {

	public static void main(String[] args) throws IOException {
		String path = &quot;hoge.txt&quot;;
		Writer out = new FileWriter(path);
		out.write(&quot;foo&quot;);
		out.write(&quot;bar&quot;);
		out.close();
		System.out.println(&quot;END&quot;);
	}

}

Writerのデコレータを使う

WriterSample2.java

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class WriterSample2 {

	public static void main(String[] args) throws IOException {
		String path = &quot;hoge.txt&quot;;
		PrintWriter out = new PrintWriter(
				new BufferedWriter(new FileWriter(path)));
		out.println(&quot;foo&quot;);
		out.println(&quot;baa&quot;);
		out.close();
		System.out.println(&quot;END&quot;);
	}
}

Readerを使う

ReaderSample.java

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReaderSample {

	public static void main(String[] args) throws IOException {
		String path = &quot;hoge.txt&quot;;
		BufferedReader in = new BufferedReader(new FileReader(path));
		String line;
		while ((line = in.readLine()) != null) {
			System.out.println(line);
		}
		in.close();
	}

}

バイナリデータの入出力

OutputStreamを使う

OutputSample.java

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


public class OutputSample {

	public static void main(String[] args) throws IOException {
		String path = &quot;btest.bin&quot;;
		OutputStream out = new FileOutputStream(path);
		byte[] b = new byte[] {0x0a, 0x0b, 0x0c};
		out.write(b);
		out.close();
		System.out.println(&quot;END&quot;);
	}

}

InputStreamを使う

InputSample.java

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;


public class InputSample {

	public static void main(String[] args) throws IOException {
		String path = "btest.bin";
		InputStream in = new FileInputStream(path);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int len;
		byte[] b = new byte[1024];
		while (true) {
			len = in.read(b);
			if (len < 0) break;
			out.write(b, 0, len);
		}
		in.close();
		byte[] result = out.toByteArray();
		for (int i = 0; i < result.length; i++) {
			System.out.print(Integer.toHexString(result[i]) + " ");
		}
	}

}

ファイルをコピーする

FileCopy.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileCopy {

	public static void main(String[] args) throws IOException {
		String src = "hoge.txt";
		String dest = "hoge2.txt";
		InputStream in = new FileInputStream(src);
		OutputStream out = new FileOutputStream(dest);
		int len;
		byte[] b = new byte[1024];
		while (true) {
			len = in.read(b);
			if (len < 0) break;
			out.write(b, 0, len);
		}
		in.close();
		out.close();
		System.out.println("END");
	}

}

必ずcloseする

CloseSample.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


public class CloseSample {

	public static void main(String[] args) throws IOException {
		String src = "hoge.txt";
		String dest = "hoge2.txt";
		copy(dest, src);
	}

	public static void copy(String dest, String src) throws IOException {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new FileInputStream(src);
			out = new FileOutputStream(dest);
			int len;
			byte[] b = new byte[1024];
			while (true) {
				len = in.read(b);
				if (len < 0) break;
				out.write(b, 0, len);
			}
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {}
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {}
			}
		}
	}
}

Java7から自動でcloseしてくれる機能が追加された。
try-with-resources文を使うと自動的にcloseしてくれる。
自動でcloseしてくれるオブジェクトは、AutoClosableインタフェースを実装しているクラス。

CloseSample2.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class CloseSample2 {

	public static void main(String[] args) throws IOException {
		String src = "hoge.txt";
		String dest = "hoge2.txt";
		copy(dest, src);
	}

	public static void copy(String dest, String src) throws IOException {
		try (InputStream in = new FileInputStream(src);
			 OutputStream out = new FileOutputStream(dest)) {
			int len;
			byte[] b = new byte[1024];
			while (true) {
				len = in.read(b);
				if (len < 0) break;
				out.write(b, 0, len);
			}
		}
	}

}

Webページのコピー(ファイル以外の例)

DownloadSample.java を try-with-resources構文で書き換えてみる。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

public class DownloadSample {

	public static void main(String[] args) throws IOException {
		String dest = "dest.html";
		URL url = new URL("http://www.yahoo.co.jp/");
		try (
				InputStream in = url.openStream();
				OutputStream out = new FileOutputStream(dest)
			) {
			int len;
			byte[] b = new byte[1024];
			while (true) {
				len = in.read(b);
				if (len < 0) break;
				out.write(b, 0, len);
			}
		}
	}
}

Fileクラスを使う

FileSample.java

import java.io.File;

public class FileSample {

	public static void main(String[] args) {
		File file = new File("C:/All-in-One-Eclipse4.4/workspace/c24/");
		list(file);
	}

	private static void list(File parent) {
		File[] children = parent.listFiles();
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				File file = children[i];
				if (file.isDirectory()) {
					list(file);
				} else {
					System.out.println(file.getAbsolutePath());
				}
			}
		}
	}
}

Dirコマンドを作ってみよう

Dir.java

import java.io.File;

public class Dir {

	public static void main(String[] args) {
		File file = new File(args[0]);
		dir(file);
	}

	private static void dir(File parent) {
		File[] children = parent.listFiles();
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				File file = children[i];
				System.out.println(file.getName());
			}
		}
	}

}
  1. 引数なしの場合、現在のディレクトリの内容を表示する
  2. /OS オプションが指定されたらサイズ順にソートする
  3. /OD オプションが指定されたら日付順にソートする

引数なしの場合、現在のディレクトリの内容を表示する

Dir.java

import java.io.File;

public class Dir {

	public static void main(String[] args) {
		String path;
		if (args.length == 0) {
			path = ".";
		} else {
			path = args[0];
		}
		File file = new File(path);
		dir(file);
	}

	private static void dir(File parent) {
		File[] children = parent.listFiles();
		if (children != null) {
			for (int i = 0; i < children.length; i++) {
				File file = children[i];
				System.out.println(file.getName());
			}
		}
	}
}

オプションの取得と条件分岐

Dir.java

import java.io.File;

public class Dir {

	public static void main(String[] args) {
		String path;
		String option = null;
		if (args.length == 0) {
			path = ".";
		} else {
			path = args[0];
			option = getOption(args);
		}
		File file = new File(path);
		dir(file, option);
	}

	private static String getOption(String[] args) {
		for (String s : args) {
			if (s.startsWith("/")) {
				return s;
			}
		}
		return null;
	}

	private static void dir(File parent, String option) {
		File[] children = parent.listFiles();
		if (children != null) {
			if (option == null) {
				for (int i = 0; i < children.length; i++) {
					File file = children[i];
					System.out.println(file.getName());
				}
			}
			if (option.equals("/OD")) {
				// 日付順
			}
			if (option.equals("/OS")) {
				// サイズ順
			}
		}
	}

}

5月11日

コレクションフレームワーク

Set

Setは重複のないコレクション。すでに存在するものをadd()した場合は、falseが返される。

SetSample.java

import java.util.HashSet;
import java.util.Set;

public class SetSample {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("東京");
		set.add("ロンドン");
		set.add("パリ");
		for (String item : set) {
			System.out.println(item);
		}
	}
}

SetSample2は、SetインタフェースをCollectionインタフェースに置き換えただけ。
JavaDocでCollectionインタフェースを確認すると、ListやSetで使用したメソッドが定義されていることがわかる。

Eclipseの機能を使用してSetSample3.javaを作成する。

  1. SetSample.javaの上で右クリックしコピーを選択
  2. デフォルトパッケージの上で右クリックし貼り付けを選択
  3. クラス名が CopyOfSetSample になっているので、これを SetSample3 に修正してOKする
  4. これでSetSampleの内容がSetSample3.javaにコピーされる

SetSample.javaと異なる部分を入力してSetSample3.javaを作成する。

import java.util.HashSet;
import java.util.Set;

public class SetSample3 {

	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("東京");
		set.add("ロンドン");
		set.add("パリ");

		if (!set.add("ロンドン")) {
			System.out.println("ロンドンは追加できない");
		}
		if (set.contains("ロンドン")) {
			System.out.println("ロンドンはある");
		}
		for (String item : set) {
			System.out.println(item);
		}
	}
}

テキストにはない例題をやってみる。

  1. ListSample6.javaのmainメソッド内をコピーする
  2. SetSample6.javaのmainメソッドに貼り付ける
  3. ListをSetに変更する
  4. ArrayListをHashMapに変更する
  5. 変数listにカーソルを置きメニューのリファクタリングを選択
  6. 変数名listをset変更すると、すべてのlistがsetに変更される(便利!)

SetSample4.java

import java.util.HashSet;
import java.util.Set;

public class SetSample4 {
	public static void main(String[] args) {
		Set<Man> set = new HashSet<Man>();
		set.add(new Man("孫", 10));
		set.add(new Man("北尾", 15));
		set.add(new Man("三木谷", 20));
		if (!set.add(new Man("孫", 10))) {
			System.out.println("孫は追加できない");
		}
		for (Man man : set) {
			System.out.println(man);
		}
	}
}

これを実行すると、二人目の孫が追加できてしまう。
二人目の孫を追加できないようにコードを修正する。

Man.javaを修正する。

  1. Man.javaを開く
  2. メニューの ソース を選択する
  3. hashCode()およびequeals()の生成 を選択する
  4. ageとnameにチェックが入った状態でOKする

これで、Man.java にhashCode()とequals()のオーバーライドが生成される。

Man.java

public class Man {
	String name;
	int age;
	Man(String name, int age) {
		this.name = name;
		this.age = age;
	}
	void introduce() {
		System.out.println("僕は" + name + " 年は" + age);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Man other = (Man) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return super.toString() + "[name=" + name + ", age=" + age + "]";
	}
}

SetSample4.java を実行すると「孫は追加できない」と表示されるようになる。

Mapの利用

Mapはキーに対応した値を持つ集合。

MapSample.java

import java.util.HashMap;
import java.util.Map;

public class MapSample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("red", "赤");
		map.put("blue", "青");
		map.put("yellow", "黄色");
		String value = map.get("blue");
		System.out.println(value);
	}
}

要素を一覧する

MapSample2を作るまでもないので、MapSample.javaを修正して試す。

import java.util.HashMap;
import java.util.Map;

public class MapSample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("red", "赤");
		map.put("blue", "青");
		map.put("yellow", "黄色");
		//String value = map.get("blue");
		//System.out.println(value);
		for (String key : map.keySet()) {
			String value = map.get(key);
			System.out.println(key + "=" + value);
		}
	}
}

Iteratorを使った走査

Iteratorインタフェースを使って要素の走査をすることもできる。

IteratorSample.java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorSample {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("東京");
		list.add("ロンドン");
		list.add("パリ");
		Iterator<String> iter = list.iterator();
		while (iter.hasNext()) {
			String item = iter.next();
			System.out.println(item);
		}
	}
}

配列とListの変換

配列からListへの変換はArraysクラスのstaticメソッドasList()を使用する。
Listから配列への変換はListインタフェースのtoArray()メソッドを使用する。

ArraySample.java

import java.util.Arrays;
import java.util.List;

public class ArraySample {
	public static void main(String[] args) {
		String[] array = new String[] {"東京", "ロンドン", "パリ"};
		// 配列→リスト
		List<String> list = Arrays.asList(array);
		System.out.println("list");
		for (String s : list) {
			System.out.println(s);
		}
		// List→配列
		String[] array2 = list.toArray(new String[0]);
		System.out.println("array");
		for (String s : array2) {
			System.out.println(s);
		}
	}
}

ソートとComparator

Collectionsクラスのsort()メソッドを使って文字列をソートする例。

SortSample.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SortSample {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("いいい");
		list.add("ううう");
		list.add("あああ");
		Collections.sort(list);
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}
	}
}

ソート順序をカスタマイズする

ソート順序をカスタマイズするには java.util.Comparator インタフェースを実装したクラスを作成し、sort()メソッドの第2引数に渡す。

SortSample2.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortSample2 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("いい");
		list.add("う");
		list.add("あああ");
		class MyComparator implements Comparator<String> {
			@Override
			public int compare(String o1, String o2) {
				return o1.length() - o2.length();
			}
		}
		Collections.sort(list, new MyComparator());
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}
	}
}

無名クラスを使ったコードを追加する。

24行目で新しい要素を追加。
25~30行は、Collections.sort()メソッドの呼び出しで無名クラスのComparatorを第2引数に渡した例。
31~34行で結果の出力。

SortSample2.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortSample2 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("いい");
		list.add("う");
		list.add("あああ");
		class MyComparator implements Comparator<String> {
			@Override
			public int compare(String o1, String o2) {
				return o1.length() - o2.length();
			}
		}
		Collections.sort(list, new MyComparator());
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}

		list.add("ええ");
		Collections.sort(list, new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return o1.length() - o2.length();
			}
		});
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}
	}
}

引数が1個のsort()メソッドに渡すListは、Comparableインタフェースを実装しているクラスを格納しておかなければいけない。
Comparableインタフェースを実装していないManを格納したListを渡すコードを書いてみる。

SortSample2.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class SortSample2 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("いい");
		list.add("う");
		list.add("あああ");
		class MyComparator implements Comparator<String> {
			@Override
			public int compare(String o1, String o2) {
				return o1.length() - o2.length();
			}
		}
		Collections.sort(list, new MyComparator());
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}

		list.add("ええ");
		Collections.sort(list, new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return o1.length() - o2.length();
			}
		});
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}

		List<Man> list2 = new ArrayList<Man>();
		Collections.sort(list2);
	}
}

Collections.sort(list2);の部分でコンパイルエラーになる。
Manクラスをimplements Comparable し、compareTo()メソッドを追加するとエラーが解消する。

Man.java


public class Man implements Comparable<Man>{
	String name;
	int age;
	Man(String name, int age) {
		this.name = name;
		this.age = age;
	}
	void introduce() {
		System.out.println("僕は" + name + " 年は" + age);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Man other = (Man) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return super.toString() + "[name=" + name + ", age=" + age + "]";
	}
	@Override
	public int compareTo(Man o) {
		return 0;
	}
}

5月8日

WordPressのURL: http://abc2015.satoshis.jp/

Eclipseに慣れる

テキストp.406 まとめ

Eclipseでプログラミングするときの手順。

プロジェクトを作る

  1. [新規]-[Javaプロジェクト]
  2. プロジェクト名を入力
  3. 「完了」

クラスを作る

  1. [新規]-[クラス]
  2. パッケージ名を指定(プロジェクト名が入っているので消す)
  3. クラス名を入力
  4. 完了をクリック

21章 例外とアサーション

まとめの練習問題
Renshu.java

import java.io.IOException;

public class Renshu {

	public static void main(String[] args) throws IOException {
		foo(10);
		bar(20);
	}

	static void foo(int a) throws IllegalArgumentException {
		//
	}

	static void bar(int b) throws IOException {
		//
	}
}

Renshu2.java

class FooException extends Exception {

}

public class Renshu2 {

	public static void main(String[] args) {
		try {
			foo();
		} catch (FooException e) {
			System.out.println(e);
		}
	}

	private static void foo() throws FooException {
		throw new FooException();
	}

}

22章 クラスを使いこなす

ネストクラス

ネストクラスには、以下の3種類がある。

  • メンバクラス
  • ローカルクラス
  • 無名クラス

ガベージコレクション

ガベージコレクションは、不要になったインスタンスが使用したメモリ領域を自動的に解放する仕組み。

列挙型

列挙型は定数の集合を扱うための型。

BloodType.java


public enum BloodType {
	A,
	B,
	AB,
	O
}

EnumSample.java

public class EnumSample {

	public static void main(String[] args) {
		BloodType bloodType = BloodType.A;
		System.out.println("bloodType=" + bloodType);
	}

}

EnumSample2.java


public class EnumSample2 {

	public static void main(String[] args) {
		BloodType type = BloodType.valueOf("B");
		System.out.println(type.name());
		System.out.println(type == BloodType.A);
		System.out.println(type == BloodType.B);
		BloodType[] values = BloodType.values();
		for (BloodType value : values) {
			System.out.print(value + ",");
		}
	}

}

static import

static import することで、他のクラスのstaticメンバに直接アクセスできるようになる。

StaticImportSample.java

import static java.lang.Math.*;

public class StaticImportSample {

	public static void main(String[] args) {
		double pi = PI;
		System.out.println(pi);
		int num = abs(-10);
		System.out.println(num);
	}

}

23章 コレクション

コレクションでは、主に3つの種類がよく使われる。

  • List
  • Set
  • Map

ListSample.java(警告が表示されるが、ここでは無視)

import java.util.ArrayList;

public class ListSample {

	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add("東京");
		list.add("ロンドン");
		list.add("パリ");
		list.add(new Integer(1));
		for (int i = 0; i < list.size(); i++) {
			String item = (String)list.get(i);
			System.out.println(i + ":" + item);
		}
	}

}

ジェネリックス

ジェネリックスを使って型引数を指定する。
コレクションフレームワークでは、標準ではObject型を扱うが、ジェネリックスによって特定の型のみを扱えるように制限する。

ListSample3.java

import java.util.ArrayList;
import java.util.List;


public class ListSample3 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("東京");
		list.add("ロンドン");
		list.add("パリ");
		for (int i = 0; i < list.size(); i++) {
			String item = list.get(i);
			System.out.println(i + ":" + item);
		}
	}

}

自作クラスの利用

コレクションフレームワークでは、自作クラスも利用できる。

Man.java


public class Man {
	String name;
	int age;
	Man(String name, int age) {
		this.name = name;
		this.age = age;
	}
	void introduce() {
		System.out.println("僕は" + name + " 年は" + age);
	}
}

ListSample5.java

import java.util.ArrayList;
import java.util.List;


public class ListSample5 {

	public static void main(String[] args) {
		List<Man> list = new ArrayList<Man>();
		list.add(new Man("孫", 10));
		list.add(new Man("北尾", 15));
		list.add(new Man("三木谷", 20));
		for (int i = 0; i < list.size(); i++) {
			Man man = list.get(i);
			man.introduce();
		}
	}

}

拡張for文で走査する

ListSample6.java

import java.util.ArrayList;
import java.util.List;

public class ListSample6 {

	public static void main(String[] args) {
		List<Man> list = new ArrayList<Man>();
		list.add(new Man("孫", 10));
		list.add(new Man("北尾", 15));
		list.add(new Man("三木谷", 20));
		for (Man man : list) {
			System.out.println(man);
		}
	}

}

このままでは出力結果がよくわからないので、ManクラスでtoString()メソッドをオーバーライドする。

Man.java


public class Man {
	String name;
	int age;
	Man(String name, int age) {
		this.name = name;
		this.age = age;
	}
	void introduce() {
		System.out.println("僕は" + name + " 年は" + age);
	}

	@Override
	public String toString() {
		return super.toString() + "[name=" + name + ", age=" + age + "]";
	}
}