BullよりElk

洋服と食をこよなく愛するWebプログラマ。

ボンジョルノ!美味しい国イタリア!

長期休暇を取得できたのでミラノへ旅行に行きました。
昨年の5月にバルセロナに行ってから2度目のヨーロッパ。
f:id:b1a9id:20170329214312p:plain

せっかくなので旅行記でも書こうかと思います。

まずは、一番楽しみにしていた食べ物について。
食べたものは、クロワッサン、マルガリータ、チーズ盛り合わせ、サラミ盛り合わせ、パニーニ、ミラノ風カツレツ、ミラノ風リゾット、ジェラート、Tボーンステーキ、チーズケーキ、カルボナーラ、ティラミス、5フォルマッジなどです。
イタリアならではなものは大体食べましたー
f:id:b1a9id:20170329214441j:plain

クロワッサンは、何でもないカフェのものでもかなりおいしいです。
チーズ盛り合わせは、ライトなチーズから順に食べるんだよとお店の人に教えてもらいました。
あとは、いろんなレストランに行きました。どれもだいたい量が多いです。イタリアに行かれる方は、半分で注文するのもありだと思います。
レストランでは、お通しがパンの盛り合わせですので炭水化物を頼みすぎるとつらいです。笑
ジェラテリアは想像以上にたくさんお店がありますので甘党の方は楽しいと思います。
f:id:b1a9id:20170329214446j:plain

その他。イタリア人の食生活を見てて思ったことです。

1.ピザの耳は食べない。

耳まで食べちゃうと全部食べられないし、太るかららしいです。

2.朝ごはんはあんまり食べない。

食べてる人もいましたけど朝から甘いパンとエスプレッソっていう方がほとんどです。
一番びっくりしたのは、パンがおいてあるショーケースの上で普通にモーニングしていたことです。
ランチが長い分朝はちゃちゃっと済ませたいのかな?って感じました。

3.ビールより圧倒的にワインを飲む

f:id:b1a9id:20170329214443j:plain

次に、文化について。
つらつらと書きならべてみます。
・電車は普通に遅れる。
・電車のホームの場所は固定でなく、5~10分前にわかる。
・ありがとう、どいたしましてが日常茶飯事。
・百貨店にもナチュラルに大型犬がいる。
f:id:b1a9id:20170329214436j:plain

次にファッションについて。
普通におしゃれな人は多いです。女性は大体スキニーデニムでした。スカートをはいている人はほぼいなかったです。
男性も細身なパンツが多いです。私は、太めのパンツで言ってたので結構視線を感じました。笑
あと、モノトーンが男女とも好きですね。
フィレンツェはほんとにレザーショップは多くて安かったです。
ミラノでオールレザーのリュックを買いましたが185ユーロと激安だったので即買いました。
f:id:b1a9id:20170329214420j:plain

まとめ。
ポルタガリバルディ駅付近はそんなに人も多くなく、怖そうな人もほぼいないので安心して泊まれると思います。
ミラノ中央駅付近は、ホテルは多いですが中心駅ということでホームレスみたな人は多かったです。
イタリアに行く際は、「ありがとう」と「どういたしまして」は覚えてたほうが良いと思います。
食べるのとファッションが好きな人はミラノフィレンツェはとてもとても楽しいと思います!!!
f:id:b1a9id:20170329214531p:plain

バブルソート

バブルソートは最も単純な整列法です。

バブルソートアルゴリズム

  1. 配列の末尾から先頭に向かって隣り合う要素を比較する
  2. 後ろの要素が前の要素よりも小さければ交換する
  3. 1と2を繰り返す

以下が、バブルソートJavaプログラムです。

import java.util.Arrays;

public class BubbleSort {
	public static void main(String[] args) {
		int[] array = {2, 5, 8, 6, 10, 1, 3, 7, 9, 4};

		for (int i = 0; i < array.length - 1; i++) {
			for (int j = array.length - 1; j > i; j--) {
				if (array[j - 1] > array[j]) {
					int x = array[j - 1];
					array[j - 1] = array[j];
					array[j] = x;
				}
			}
		}

		Arrays.stream(array).forEach(System.out::println);
	}
}

出力結果

1
2
3
4
5
6
7
8
9
10

参考:基礎から学ぶデータ構造とアルゴリズム 著:穴田有一・林雄二

Spring Actuatorが誰でもみれなくなっちゃったの巻

Spring Actuatorで登録されてるBeanをみようと思って、pom.xmlにSpring Actuatorを追加しました。(以下参照)
Versionはご自由にどうぞ!

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>1.5.1.RELEASE</version>
</dependency>

そして「http://localhost:8080/beans」にアクセース!
「401:Unauthorized」が返ってきました。あれ?と思いログ見ると次の出力が!
「Full authentication is required to access actuator endpoints. Consider adding Spring Security or set 'management.security.enabled' to false.」
仕様変わったのか!(前記事で見たような)と思いログの出力のとおりに。
まず、pom.xmlにこれを追加。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

次に、application.propertiesにこれを追加。

management.security.enabled=false

再度、「http://localhost:8080/beans」にアクセース!よし見れた!
f:id:b1a9id:20170313175839p:plain

もしくは、ユーザにACTUATORを権限をつけるとみれます。

ちなみに、Spring Securityを使うとデフォルトでベーシック認証が有効になっているので無効にする場合は、application.propertiesに以下を追加してください。

security.basic.enabled=false

Portaille 2017AW 展示会

今日は、恵比寿で開催されていたPortaille 2017AW 展示会に行ってきました!
www.instagram.com

毎回興奮するものばっかり見れるから今回も1ヶ月前からわくわく♪

寝坊したため予定より1時間遅れで入りました〜
1番目立っていたボルドーをまず試着。今回からの新しい形だそうで。しかも皮もかなり珍しいやつでした。(やばいとしか言いようがない)
f:id:b1a9id:20170311161534j:plain
f:id:b1a9id:20170311161537j:plain

次にバックジップのブラウン
f:id:b1a9id:20170311161831j:plain
これも素敵でした〜

居心地よすぎて2時間も話し込んでしまいました〜w
皮の話からどういう思いで作ってるかとかまでいっぱい話したけど専門的な話多くてあんまり覚えていなけどすごく楽しかったです♪
大渕夫妻ほんといい人たち!!!

気になった人は是非調べてみてください。
ちなみにすごく迷ってボルドーを買いました!8月に届くので今年の秋は例年以上に楽しみ!

再来週からイタリア行くけど、フィレンツェにフェラガモ博物館あること教えてもらったので是非行ってみます!

はじめてのVagrant

Vagrantをちょっとみました。インストール手順まとめました。

Vagrant?ってなった人は、これをお勧めします。
Vagrant導入手順から本ブログに記載します!
qiita.com

1.Vagrantをインストール

これを参考にしました。
qiita.com

brew cask install virtualbox
brew cask install vagrant
brew cask install vagrant-manager

2.VMディレクトリの作成

mkdir -p ~/vm/vm-dir/
cd ~/vm/vm-dir/

3.Vagrantfileの生成

私は、CentOS7を使います。

vagrant init --minimal  centos/7

4.VMの起動とSSHログイン

VMを起動します。

vagrant up
==> default: Checking if box 'centos/7' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: No guest additions were detected on the base box for this VM! Guest
    default: additions are required for forwarded ports, shared folders, host only
    default: networking, and more. If SSH fails on this machine, please install
    default: the guest additions and repackage the box to continue.
    default:
    default: This is not an error message; everything may continue to work properly,
    default: in which case you may ignore this message.
==> default: Rsyncing folder: /Users/hoge/vm/vm-dir/ => /vagrant
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.

起動状況の確認

vagrant status
Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.

SSHログイン

vagrant ssh
[vagrant@localhost ~]$

SSHログインできました。
ちなみに、「VMのシャットダウンは vagrant halt, 休止は vagrant suspend です。」

疑問1)boxって何?
公式ドキュメントより。boxとは、Vagrant環境のためのパッケージフォーマットと書いてあるけど。よくわからん。
www.vagrantup.com

Java標準ライブラリを学ぶ #1

Javaエンジニア養成読本を読んで気になったところをまとめていこうと思います。

今回は第4章。

文字列を扱う

文字列を比較するときに気をつけること

  • 「==」は使用できない

Stringクラスはnew演算子インスタンスを生成することが稀なため、インスタンスの識別が曖昧になりがち。
文字列リテラルは常にインスタンスを生成するわけでなく、生成済みの場合は同じインスタンスが共有される。Stringクラスのインスタンスをnew演算子で各々生成すれば、同じ文字列であっても、==演算子でfalseを返す。
文字列の一致を検証したい場合は、equals()メソッドを使用する。

文字列の連結で知っておくべきこと

+で文字列の連結が可能だが、連結されるたびに新たなインスタンスが生成される。そのため、連続して連結する場合は、StringBuilderクラスを使用するのが一般的。
Java SE8 にてStringクラスに文字列を区切り文字つきで連結するjoin()メソッドが追加された。

Stringクラスはイミュータブル

replace()メソッドなどの状態を変化させそうなメソッドも自身のインスタンスは変更せず、別のインスタンスを返すようになっている。

実際にいろんな文字列連結パターンの所要時間出して見ました。コードはこれ。
次のブログから知恵をお借りしました。
calms.hatenablog.com

public class TestString {
	public static void main(String[] args) {
		String val1 = "abcde";
		String val2 = "fghij";
		String val3 = "klmno";
		String val4 = "pqrst";
		String val5 = "uvwxyz";

		long startTime1 = System.currentTimeMillis();
		String message1 = null;
		for (int i = 0; i < 100000000; i++) {
			message1 = val1 + val2;
			message1 += val3;
			message1 += val4;
			message1 += val5;
		}
		long endTime1 = System.currentTimeMillis();
		System.out.println("+で連結の所要時間(ms) : " + (endTime1 - startTime1));

		long startTime2 = System.currentTimeMillis();
		String message2 = null;
		for (int i = 0; i < 100000000; i++) {
			StringBuilder buf2 = new StringBuilder();
			buf2.append(val1);
			buf2.append(val2);
			buf2.append(val3);
			buf2.append(val4);
			buf2.append(val5);
			message2 = buf2.toString();
		}
		long endTime2 = System.currentTimeMillis();
		System.out.println("StringBuilderで連結の所要時間(ms) : " + (endTime2 - startTime2));

		long startTime3 = System.currentTimeMillis();
		String message3 = null;
		StringBuilder buf3 = new StringBuilder();
		for (int i = 0; i < 100000000; i++) {
			buf3.setLength(0);
			buf3.append(val1);
			buf3.append(val2);
			buf3.append(val3);
			buf3.append(val4);
			buf3.append(val5);
			message3 = buf3.toString();
		}
		long endTime3 = System.currentTimeMillis();
		System.out.println("StringBuilder&setLength(0)で連結の所要時間(ms) : " + (endTime3 - startTime3));

		long startTime4 = System.currentTimeMillis();
		String message4 = null;
		for (int i = 0; i < 100000000; i++) {
			StringBuilder buf4 = new StringBuilder(val1);
			buf4.append(val2);
			buf4.append(val3);
			buf4.append(val4);
			buf4.append(val5);
			message4 = buf4.toString();
		}
		long endTime4 = System.currentTimeMillis();
		System.out.println("StringBuilder&new StringBuilder(val1)で連結の所要時間(ms) : " + (endTime4 - startTime4));

		long startTime5 = System.currentTimeMillis();
		String message5 = null;
		for (int i = 0; i < 100000000; i++) {
			message5 = val1 + val2 + val3 + val4 + val5;
		}
		long endTime5 = System.currentTimeMillis();
		System.out.println("+で一気に連結の所要時間(ms) : " + (endTime5 - startTime5));
	}
}

ちなみに結果は、こんな感じです。
=======
+で連結の所要時間(ms) : 6387
StringBuilderで連結の所要時間(ms) : 7995
StringBuilder&setLength(0)で連結の所要時間(ms) : 4869
StringBuilder&new StringBuilder(val1)で連結の所要時間(ms) : 8711
+で一気に連結の所要時間(ms) : 2991
=======

5番目の連結方法が圧倒的に早いです!

ユニットテストのナレッジ #1

1ヶ月ぶりに更新します。今年はもっとインプットを増やしてアウトプットも増やしていこうと思います!

まずテスト対象クラスはこちらのShopService.java

@Service
public class ShopService {

	@Autowired
	private ShopRepository shopRepository;

	public Shop getShop(Integer id) {
		return shopRepository.findOne(id);
	}

	public Shop create(ShopCreateRequest request) {
		LocalDateTime now = LocalDateTime.now();

		Shop shop = new Shop();
		shop.setGenre(request.getGenre());
		shop.setShopName(request.getShopName());
		shop.setStation(request.getStation());
		shop.setUrl(request.getUrl());
		shop.setMemo(request.getMemo());
		shop.setCreatedAt(now);

		return shopRepository.saveAndFlush(shop);
	}

	public Shop edit(Integer id, ShopEditRequest request) {
		Shop shop = getShop(id);
		shop.setGenre(request.getGenre());
		shop.setShopName(request.getShopName());
		shop.setStation(request.getStation());
		shop.setUrl(request.getUrl());
		shop.setMemo(request.getMemo());

		return shopRepository.saveAndFlush(shop);
	}
}

続いてテストクラスは、ShopService.java

import com.uchitate.core.entity.Shop;
import com.uchitate.core.repository.ShopRepository;
import com.uchitate.web.support.Genre;
import com.uchitate.web.support.ShopCreateRequest;
import com.uchitate.web.support.ShopEditRequest;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;

@RunWith(HierarchicalContextRunner.class)
public class ShopServiceTest {

	@InjectMocks
	private ShopService shopService;

	@Mock
	private ShopRepository shopRepository;

	@Captor
	private ArgumentCaptor<Shop> captor;

	@Before
	public void setup() {
		MockitoAnnotations.initMocks(this);
	}

	public class Create {
		private ShopCreateRequest generateShopCreateRequest(
				Genre genre,
				String shopName,
				String station,
				String url,
				String memo) {
			ShopCreateRequest request = new ShopCreateRequest(genre, shopName, station, url, memo);
			return request;
		}

		@Test
		public void success() {
			ShopCreateRequest request = generateShopCreateRequest(
					Genre.JAPANESE,
					"定食屋1",
					"渋谷",
					"http://teisyoku-1.co.jp",
					"トンカツが有名");

			shopService.create(request);
			Mockito.verify(shopRepository).saveAndFlush(captor.capture());
			Shop savedShop = captor.getValue();
			Assertions.assertThat(savedShop)
					.extracting(Shop::getGenre, Shop::getShopName, Shop::getStation, Shop::getUrl, Shop::getMemo)
					.contains(Genre.JAPANESE, "定食屋1", "渋谷", "http://teisyoku-1.co.jp", "トンカツが有名");
		}
	}

	public class Edit {
		private ShopEditRequest generateShopEditRequest(
				Genre genre,
				String shopName,
				String station,
				String url,
				String memo) {
			ShopEditRequest request = new ShopEditRequest(genre, shopName, station, url, memo);
			return request;
		}

		private Shop generateShop(int id, Genre genre, String shopName, String station, String url, String memo) {
			Shop shop = new Shop();
			shop.setId(id);
			shop.setGenre(genre);
			shop.setShopName(shopName);
			shop.setStation(station);
			shop.setUrl(url);
			shop.setMemo(memo);
			return shop;
		}

		@Test
		public void success() {
			ShopEditRequest request = generateShopEditRequest(
					Genre.JAPANESE,
					"定食屋1",
					"渋谷",
					"http://teisyoku-1.co.jp",
					"トンカツが有名");

			Shop shop = generateShop(1, Genre.ITALIAN, "イタリアン1", "代官山", "http://italian-1.co.jp", "ピザ");

			Mockito.when(shopRepository.findOne(Mockito.anyInt())).thenReturn(shop);

			shopService.edit(1, request);
			Mockito.verify(shopRepository).saveAndFlush(captor.capture());
			Shop savedShop = captor.getValue();
			Assertions.assertThat(savedShop)
					.extracting(Shop::getGenre, Shop::getShopName, Shop::getStation, Shop::getUrl, Shop::getMemo)
					.contains(Genre.JAPANESE, "定食屋1", "渋谷", "http://teisyoku-1.co.jp", "トンカツが有名");
		}
	}
}

では、解説。

@RunWith(HierarchicalContextRunner.class)

ランナーは、「HierarchicalContextRunner.class」を指定します。
github.com
このクラスは、テストクラスの階層構造を可能にします。ただそれだけといえばそれだけです。
見た目が美しくなります。私は、テスト対象クラスのメソッド単位でテストクラスを作ってます。


まず、pom.xmlに以下を追加します。

<dependency>
    <groupId>de.bechte.junit</groupId>
    <artifactId>junit-hierarchicalcontextrunner</artifactId>
    <version>4.12.1</version>
</dependency>

あとは、

@RunWith(HierarchicalContextRunner.class)

と書くだけです。

@InjectMocks

このクラスにモックを注入しますよアノテーション

@Mock

モックにするよアノテーション

@Captor

好きなところの状態のオブジェクトを取得したいよアノテーション

@Captor
private ArgumentCaptor<Shop> captor;

Shop.javaのオブジェクトを取得することを指定します。
次をテスト対象クラスのメソッドを呼んだあとに書きます。

Mockito.verify(shopRepository).saveAndFlush(captor.capture());
Shop savedShop = captor.getValue();

これで、「shopRepository.saveAndFlush(shop);」を呼ぶ時に渡す引数のオブジェクトを取得します。

editは、ほぼ同じなので省略します。
以上、ユニットテストのナレッジ #1でした〜