IntelliJ KEYMAP #1(Mac)

何回かに分けてIntelliJのKEYMAPについて紹介したいと思います!
1回目は、Editingです。ちなみにKeymapは、Mac OS Xです。異なる方はちょいと変わってくると思います!

ショートカットキー 説明
^ Space ベーシックなコード補完(いくつかクラスやメソッドや変数の候補をあげる)
^ Shift Space スマートなコード補完(そのメソッドで期待されるタイプの変数の候補をあげる)
Command P パラメータ情報表示
^ J クイックドキュメント表示
Command コードをマウスオーバー 簡単なドキュメント表示
^ N GetterやSetterやConstructorなどのコードを生成
Command O オーバーライドメソッドの表示
Command Option T if...elseやtry...catchなどの雛形コード生成
Command / カーソルがある行のコメントアウト
^ Shift Q コンテキスト情報の表示。puclic class Test extends Hoge { を表示
Command Option L コードフォーマット
^ Shift O import文の整理。使ってないものの削除やソートを行う
Command D カーソルがある行を下に向かってコピペを行う
Command Enter カーソルがある箇所から改行する
Shift Enter カーソルがある行の次の行に空行を追加
Command Shift [ カーソルがある箇所のブロックの始まりからカーソルの箇所まで選択
Command Shift ] カーソルがある箇所からブロックの終わりまで選択
Option → カーソルが単語の終わりに遷移
Option ← カーソルが単語の始まりに遷移
Command W カーソルがある単語を選択

IntelliJ Idea設定項目~備忘録~

転職先のPCのIntelliJさんを自分のカスタマイズにしました。これ毎回探してるな〜って思っててこれ書いて自分の設定まとめます。
どなたかのお助けになれればと思います。

Keymap

Keymapsは、Mac OS Xにする。
f:id:b1a9id:20170408224632p:plain

Editor

General
  • Ensure line feed at file end on Save - ON:行末の不要なスペースやタブを保存時に削除する

● Auto Import

  • Add unambiguous imports on the fly - ON:勝手にimportしてくれる
  • Optimize imports on the fly - ON:不要なimportは削除してくれる

● Appearance

  • Show line number - ON:行番号の表示
  • Show method separators - ON:メソッドの区切り線
  • Show whitespaces - ON:空白の表示
  • Case sensitive completion - None:大文字小文字を区別しないで補完

● File Encodings

  • Transparent native-to-ascii conversion - ON:native2asciiの有効化
CodeStyle
  • Line separator (for new files) - Unix and OS X(\n):改行コード

Plugin

  • Lombok plugin:Lombok使うならいれなきゃだめ
  • A prevent pinned tabs from closing plugin - by momomo.com:固定したタブを閉じられなくするプラグイン
  • RegexpTester:正規表現を試せる
  • Save Actions:ファイルを保存するときにコードに対してアクションを施せるプラグイン

とりあえずこんなもんかな。

バブルソート

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

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

  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

詳細はここに書いてあります。
48. Monitoring and management over HTTP

はじめての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でした〜