疲れたらやすむ

Javaを学ぶ上でハマったところを書いていきます。iPhoneアプリ開発や日常ネタもあるかも。

エンジニアとして新しい道に挑戦

すっかり梅雨ですね。
でも今年は例年に比べ、降水量は少なめでしょうか。
ずーっと降っている感じではないです。

この度、というか最近。
エンジニアとして次のステップへ挑戦しています。

サーバサイドからフロントエンドへ

私は今までサーバサイドの開発を行なっていました。

サーバサイドとは、DBへの読み書きやファイルの入出力などの処理を担うものです。
画面のボタンをクリックしたりすることで走る処理ですね。
言語で言うとJavaを触っていました。

それに対しフロントエンドとは、画面側の開発を行うことです。
HTMLやCSS、JavaScriptなどを扱います。
実際に目で見える部分であり、私はフロントエンドの方がやっていてやりがいを感じます。


私はITの世界に入ってすぐ、Javaを使ってサーバサイド開発を行いました。
1年半くらいですかね。
画面を触ることはなく、ひたすら中の処理を書いていました。
実際には設計の時間も結構多く、どちらかと言えばプログラムを触っている時間の方が短かったかも。

そして最近、ついに待望のフロント側を経験させてもらえることに。
やったね!!

フロントってどうなの?楽しい?

私は好きです。フロント。

なんでしょう。
今までサーバサイドばかりだったので新鮮に感じるからなのかもしれません。

ただ、個人的にHTMLやCSS、JavaScriptの知識を蓄えられるのはすごく嬉しいです。
Webアプリケーションを作ったり、ブログのデザインをカスタマイズしたりといろいろ役立ちそう。
副業とかするにしてもフロントエンドの経験は活きてきそう。

HTMLは個人的に馴染みがあるので、色んなページのHTMLを見ながら書き進められました。

でもJavaScript。
お前は聞いてないぞ!

実務経験はないですが、研修でJavaScriptは一通り学習しました。
でも苦手だったなー。
そのままのイメージを持ち続けているので、やっぱり苦手意識のままです。

これからJavaScriptの記事も少しずつ書いていこうかな。
何やらやることが多くて手詰まり感はありますけど。
Xcodeでアプリ作成やJava Goldの勉強。
どれをいつやろうかって感じですね。

話が脱線しましたが、楽しいけど難しいっていう先入観はありますね。
結局は何事も慣れが必要なのでひたすら経験を積むしかないですが。

フロント側は値の受け渡しとか頻繁にあって大変だと感じます。
HTMLからJavaScriptへ渡したり、JavaからHTMLへ渡したり。
どこがどの値を紐付いてて・・・というのを考えるとちょっと頭が痛くなります。

今後はどうなりたいか

エンジニアとしては、画面を作るフロントエンドと内部の処理を作るサーバサイド。
そしてサーバの構築を行なったりするインフラもあります。

私の目標は、全て1人で出来る様になること。

そんなに簡単な話ではないと思いますが、そうなりたいと思っています。
単純に色んな世界を知りたいのもありますし、1人でWebアプリケーションやスマホ向けアプリ開発をやりたいからです。

ただ、まずはフロント+サーバの処理を書ければ良いかな。
細かいことは抜きにして、画面と画面の項目に紐付く内部処理を書く。
それが出来れば半人前くらいにはなれそう。


私はここ数年で仕事とか技術に対する考え方が結構変わりました。
以前は仕事なんてお金をもらうためにやっているので、そこそこ頑張っていれば良いと思っていました。
もちろん自主的に勉強なんてせず、すべて業務時間の中で調べたりしていました。

でも今は将来の自分のために必死で業務に取り組んでいます。
今経験を積んでいることは、必ず自分の力になり活かせる時が来るからです。

だから家で業務でつまづいたことを予習したり復習するのは厭わないです。
むしろ詰まって良かった!くらいの気持ち。
わからないことを1つずつ覚えていけるのは非常にありがたいことです。

これからも目標に向かって頑張ろうと思います。

【Java】その条件分岐は必要?その変数は必要?

職場でコーディングをしていてふと思いました。

この変数って定義する必要があるのかなあ・・・。
定義しなくても書けるし、かと言って定義した方が何回か使いまわせる。

今回はそんな必要か必要じゃないかの判断に迷う場合について考えてみます。

必要かどうかの判断に迷う状態とは?

まず私が判断に迷う状態。

例えばこんな時です。

ソース

String[] array = new String[] { "A", "B," };

if (array.length > 0) {
	for (String s : array) {
		// 処理
	}
}

for文に入る前のif文ですね。
配列のサイズが0よりも大きければループを行う条件になっています。
一見すると理にかなっているような気もしますが、実際のところこの条件が無くてもちゃんと動きます。


変数の場合はこんな時に迷っちゃいます。

ソース

Student student = new Student("Taro", 1);

String name = student.getName();

if (null != name) {
	String str = name;
}

Studentクラスは内容の内容は省きますが、よくあるBeanのクラスです。
String型のnameとint型のidをプライベートなフィールドに持ち、ゲッターセッターが備わったやつ。
そこから、nameを一度変数に代入し、以後はその変数を条件の判定し使ったり処理に使ったりします。

ゲッター程度なら、毎回ゲッター呼んでもいいような気がしちゃいます。

私個人の考え

極論で言うと、プログラムは動けば良いのです。
プログラムが正常に動いている以上それは正解。

ただし、メンテナンスのコストとか他の人が目にする場合は可読性を少しでも高める必要があります。
基本的に会社で開発を行う場合はほとんど可読性も求められるでしょう。

以上のことから、結局は正解は時と場合によるし、これが正しいという決まりはないと思います。

でも強いて言えば、自分だけが目にするソースだとしても可読性が高いに越したことはありません。
ですので、そう言った意味では常に読みやすいコードを記述したいですよね。

基本的には、ソースは短い方がコンパクトで読みやすいと言えると思います。
しかし無理やりステップ数を減らすよりは、冗長に感じても書いておいた方が良いif文や変数もあるでしょう。
そのあたりは経験とかコーディング規約を神様にして書いていくしかないです。

それを踏まえて、先ほどの判断に迷うソースをもう一度見直して記述してみます。

判断に迷ったらこんな感じで落ち着いた

まずは最初のif文の例。

配列に対しサイズを見てからfor文で回すのは、私は不要だと思います。
サイズが0より大きければ回す場合はですけど。

ソース

String[] array = new String[] { "A", "B," };

for (String s : array) {
	// 処理
}

この状態で意味は伝わるんじゃないかなと思います。
for文の仕組み上、サイズがもし0だったとしても例外は投げませんし、1回もループせずに次の処理に移ります。


そして変数の場合。
これは結構判断が難しいですね。

今回の場合はゲッターで代入して使い回しているので、ぎりぎり不要かなと思います。

ソース

Student student = new Student("Taro", 1);

if (null != student.getName()) {
	String str = student.getName();
}

クラスの変数自体はstudentとして定義していますし、それを使ってゲッターを呼ぶのであれば毎回呼んでも良さそう。
でも、その後も4回、5回と使うなら変数に保持するのもアリかな・・・
2回や3回使う程度ならゲッターで済ましてしまうと思います。

変数に保持しない理由としては、ゲッターはメンバ変数をただ引っ張ってくるだけの処理だからです。
パッと見ても「ああ、これはクラスの中のフィールドを取り出しているだけなんだろうな。」と予測が付きますし、メソッドの処理もメンバ変数のreturnだけ。
それなら何回か使用されていても別に良いんじゃないかなという考えです。

ただし、処理が複雑なメソッドの戻り値の場合は変数に代入しておくことを薦めます。
理由はずばり、その方がわかりやすいと思うからです。

処理が複雑なメソッドを何回も呼び出すと、そのメソッドの処理を追う機会が多くなります。
呼び出す度に処理を追っていては、ソースの全貌を把握するのも時間がかかってしまいます。
多分処理的にも、同じ戻り値を扱うなら変数に格納して使った方が処理速度は早いはず。

迷わないためにもブレないルールを決める

開発には時間が付き物。
設計に時間をかけてしまうと、開発工程の工数が削られてしまう場合もあります。
そんな時にちょっとした迷いで時間を割くのはなるべく避けたいですよね。

なので、自分の中のコーディング規約をある程度決めておくと良いと思います。

その日その日で思いのままにコーディングをしてしまうと、どうしても仕上がったソースに統一感が無かったり。

ちょっと趣旨はずれますが、コメントを記述する「//」のあとに半角スペースを入れたり入れなかったりするのを統一するだけでもかなり綺麗に見えますよ。
ちなみに私は半角スペース入れる派です。

それはそうと、途中にも書きましたがプログラムなんて動いていればOKという考え方もあります。
あまり深くは考えず、自分なりの綺麗を目指しても良いのではないでしょうか。

どんどんコーディングをしていくうちに自分の定型が見つかると思います。
そしていろんな人のソースを見る。これ大事。
そこから得られるものってかなりあります。

お手本をする人を探して真似しちゃうのも全然アリ。
私は結構人のをパクっちゃうタイプなので、職場ではソースを眺めている時間が長かったりします。
そこから自分のルールを作り、この時はこう書く!と決めておくと良いと思います。

住民税の期別に第1期がない?

技術ネタではないですがちょっと気になったこと。

個人で住民税を納付されている方は6月末が第1期の納期です。
いよいよこの時期がやってきましたね。

見たくもない課税課からの封筒が、先日届いてしまいました。
中身は納税通知書と支払い用紙。

しかし、良くも悪くも私の手元に届いた納税通知書には第1期がありませんでした。

届いた納税通知書に第1期の記載がない

f:id:chibiCat:20190626003138j:plain

ご覧の通り、届いた納税通知書には第1期の記載がありません。
そして納税通知書と一緒に、第2期から第4期までの3回分の支払い用紙が同封されていました。

まさか第1期は払わなくても良い?なんて思いが頭をよぎります。

とは言え、仮に第1期に支払なくとも、その分を第2期以降に割り振られるのかな?とも考えました。
そもそもまだ払わなくて良いとは決まってもいない。

気になってしょうがなかったので課税課の方に聞いてみました。

第1期の支払いはどうするのか?

結論から言いますと、第1期の支払いはありません

ただし、です。
本来納税するはずのお金が闇に葬られるわけではありません。
第1期で支払う分は第2期から第4期までにほぼ均等に割り振られており、結果として支払うこととなります。
ですよねーって感じでした。

でもどうしてこんなことになったのでしょうか。

第1期がない理由

その原因は退職時期でした。

住民税を給料から天引きにしている状態で退職してしまうと、残った分を個人で納めなくてはなりません。
その際に、支払う金額の計算が第1期に間に合いそうにない場合は第1期が消えるみたいです。
私の場合は5月末に離職して第1期に間に合いませんでした。

時期が時期なだけに、6月末期日の第1期の分がない!?と少し焦ってしまいました。
6月以降であれば、既に第1期の支払い期日が過ぎているので第2期からなのはわかるのですが。

少しレアなケースだと思いますが、そんな理由でした。

【Java】TreeSetで独自クラスを扱う

今回はTreeSetに的を絞って解説していきます。

Setとは?ListやMapとの違い

Setとはコレクションの1つで、重複した値を持たない特徴があります。

Main.java

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

public class Main {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		set.add("apple");
		set.add("orange");
		set.add("apple");

		for(String s : set) {
			System.out.println(s);
		}
	}
}

このように同じ値をaddした場合しても

実行結果

orange
apple

重複している値は追加されていません。

Listはaddすれば問答無用で追加するのに対し、Setはaddしても重複する値があれば要素に追加されません。

Mapと比較してみると、重複する値を持たないと言う部分ではキーと似ているかもしれません。
ですが、Mapはキーに対して値を持っているため、どちらかと言えばListの方が似ているかも。

Setの種類について

Setの代表的なものとして、HashSetとTreeSetが存在します。

基本的な理解としては、
「HashSetは格納された要素をソートしないがnullを格納できる」
「TreeSetは格納された要素をソートするがnullは格納できない」
で良いかと思います。

他にもLinkedHashSetと言うものがありますが、全く使ったことがないのでよくわかっていません。
処理速度とかの話なんですかね。

TreeSetの使い方

TreeSetは格納された要素をソートするため、ソート順を決める必要があります。

IntegerやStringなどの基本的な型の場合はそのまま使用可能。
その理由は、IntegerやStringのクラス定義でComparable<T>インターフェースを実装し、compareToメソッドでソート方法を宣言しているからです。

Integerの場合は、数値が小さい順でソートされます。

Main.java

import java.util.Set;
import java.util.TreeSet;

public class Main {
	public static void main(String[] args) {
		Set<Integer> set = new TreeSet<Integer>();
		set.add(3);
		set.add(1);
		set.add(2);

		for (Integer i : set) {
			System.out.println(i);
		}
	}
}

実行結果

1
2
3

Stringの場合はアルファベット順。

Main.java

import java.util.Set;
import java.util.TreeSet;

public class Main {
	public static void main(String[] args) {
		Set<String> set = new TreeSet<String>();
		set.add("B");
		set.add("A");
		set.add("C");

		for (String s : set) {
			System.out.println(s);
		}
	}
}

実行結果

A
B
C

独自クラスでTreeSetを扱う場合

まずソート順を指定しなかった場合どうなるか見てみます。

とりあえず独自クラスを用意します。

Student.java

public class Student {
	int id;
	String name;

	public Student(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public int getId() {
		return this.id;
	}

	public String getName() {
		return this.name;
	}
}

そしてそのままTreeSetに格納してみます。

Main.java

import java.util.Set;
import java.util.TreeSet;

public class Main {
	public static void main(String[] args) {
		Set<Student> set = new TreeSet<Student>();
		set.add(new Student(2, "Jiro"));
		set.add(new Student(1, "Taro"));
		set.add(new Student(3, "Saburo"));

		for (Student s : set) {
			System.out.println(s.getId() + " : " + s.getName());
		}
	}
}

実行結果

Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

はい。
ClassCastExceptionが発生します。
これは、TreeSetで要素を並び替える際にComparable<T>型にキャストを行う処理があるためです。
つまりキャストを行うには、独自クラスにComparable<T>を実装する必要があります。

Student.java

public class Student implements Comparable<Student> {
	int id;
	String name;

	public Student(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public int getId() {
		return this.id;
	}

	public String getName() {
		return this.name;
	}

	@Override
	public int compareTo(Student o) {
		return this.id - o.id;
	}
}

これで実行してみます。
実行結果

1 : Taro
2 : Jiro
3 : Saburo

ちゃんとソートされていますね。

ちなみに、独自クラス側でComparable<T>を実装しないパターンもあります。
その場合は、使用する側でソート順を指定します。

Set<Student> set = new TreeSet<Student>(Comparator.comparing(Student::getId));

これでStudentにComparable<T>が実装されていなくても、idの昇順で問題なく動作します。
関数型インターフェースやメソッド参照が出てきて少しややこしい部分はありますが。

このあたりはJava Goldでも出題される範囲なのでぜひ押さえておきたいところです。

【Xcode】Failed to create provisioning profileの解決方法

今回はXcodeのエラーの原因と解決方法についてです。

事象

実際のエラーの状態はこんな感じです。

f:id:chibiCat:20190616175302p:plain

Failed to create provisioning profile

No profiles for 'Bundle Identifier' were found

の2つのエラーが表示されます。

このエラーが出ていると、多分ですが実機テストが出来ません。
問答無用でBuild Failedとなってしまいます。
シミュレータではビルド可能です。

原因

私の場合は、問題なく動いていたプロジェクトを削除して、再度同じ名前のプロジェクトを作成した場合にエラーが出ました。

どうやらBundle Identifierが重複しているために怒られているそうです。
物理的にプロジェクトを削除しただけではダメらしい。

そもそもBundle Identifierとは、アプリを区別出来る一意の値です。
そのため、AppStoreで公開する時に被るのは当然、ローカルでも被ってしまうことは許されないのです。

この辺りの仕様が正直よくわかりません。
一意のIDが重複してはいけないのは理解出来るのですが、そもそもプロジェクトを削除しているので平気のはず!と思ってしまいます。

解決方法

簡単に解決するなら、別名のプロジェクトを作成するのが早そうです。

結局のところ調べてもわかりませんでした。
作成したプロジェクトを消すことは想定されていないのかもしれません。

一応Derived Dataのプロジェクト削除も行いましたが効果なし。
方法は、「Xcode」→「Preferences...」の「Locations」タブを開き、Derived Dataの項目のパス内にあるプロジェクトのデータを削除。

f:id:chibiCat:20190616234711p:plain

パスの右側の矢印マークをクリックするとFinderで開いてくれると書いてありましたが私は開きませんでした。
なので、Finder上でCommand+Shift+Gでパスを貼り付けエンターで開きました。

フォルダの中身は自分で作ったプロジェクト名から始まるフォルダと謎のフォルダが2つくらい。
自作プロジェクト名が頭に付いたフォルダだけ削除してXcodeを再起動させましたが変化なしでした。


にしても困る事象ですよね。
プロジェクト削除してるのに重複扱いとは。

何かわかり次第更新します。


【2019年6月22日追記】
後日、再度Xcodeを立ち上げてみると何故かエラーが消えていました。
何ごともなくビルドも通り実機テストも出来ました。

なんでしょう。
やったことは
・キーチェーンの整理(期限切れのものを削除)
・Derived Dataの削除
・実機のiPhone側のデベロッパAppの登録解除
ぐらいですかね。
意外とOSの再起動とかが必要だった可能性もありますが。

ちなみに、再現しようとしてプロジェクトを削除後に同名のプロジェクトを作成してもエラーは出ませんでした。
なぞい。