正規表現練習のためのクラスを作った

ここ数日ずっとJava Silverの対策というか、反復練習ばかりで何かを体系的にまとめることをしていなかった。

取り敢えず試験範囲の正規表現が今後とも使っていきそうなスキルの一つであると思ったので、手っ取り早く動作を確認できるようなクラスを作った。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
	public static void example1(String str, String reg) {
		String regex = reg;
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(str);
		System.out.print("指定した文字列は:");
		if (m.find()) {
			System.out.println("指定した正規表現とマッチします");
		} else {
			System.out.println("指定した正規表現とマッチしません");
		}
	}
}

このTestクラスのexample1メソッドの機能は、第一引数に渡した文字列が第二引数の正規表現パターンをクリアするかどうかを調べるものです。
多分調べればもっとなんか優秀な機能が見つかると思うんだけど、アウトプット大事ということで自作しました。

特に1,2行目のインポート文と6~8行目のMatcherクラスのインスタンス生成、及びそのインスタンスに対して10行目でfind()で検索をかけるあたりは殆ど定型文みたいなものだと解釈してるので、困ったらこの記事のことを思い出そうと思う。

あと今更ですがブログのコードに行番号を追加しました。

ダウンキャストについてのメモ

ずーっと保留にしてたダウンキャストへの理解が多少深まったのでメモ。

ダウンキャストした際、例外が出るパターンとそうでないパターンの判別がいまいちつかなかったので拙い解釈だが書く。

①例外出力あり

// ダウンキャスト(例外出力あり)
SuperClass sp = new SuperClass();
SubClass sb = (SubClass)sp;

SuperClassクラスのインスタンスをSubClass型にキャストすると、SuperClassクラスはSubClassクラスの差分を持たないため例外が送出される。

②例外出力なし

// ダウンキャスト(例外出力なし)
SuperClass sp = new SubClass();
SubClass sb = (SubClass)sp;

SubClassクラスのインスタンスをSubClass型にキャスト。変数spが指しているのはSubClassクラスのインスタンス(の参照値)なので、それをSubClass型として扱っても何の問題もないよねという話。

Qiitaとかteratailとかの説明を読んでも以前はさっぱりだったが、今自分でまとめても同じような説明になってしまった。
そういうことにしておきましょう。

Java Silver模擬試験チャレンジ一回目

結論から言うと玉砕しました。

48/77 ≒ 62/100 (合格ラインが65%)
試験時間150minに対し15min余らせて回答終了。

初学者にとって、紫本を一周しただけで及第点取れるほどぬるい難易度ではないことを実感。
あと問題一つ一つの密度というか割かれる労力が大きいので、後半に行くに連れて徐々に脳死状態に。
試験時間150minとか余裕でしょと思ってた自分が愚かでした。知識不足で分からない問題は何分あろうが解けません。

誤答した問題を見てみると、大体テキスト序盤の範囲ほど間違ってるっぽいので、単純に痴呆で落としてる点数もかなりあるはず。
実は黒本も既に入手しているので、このまま数をこなして知識の穴を埋めていきたいところ。

今回の点数はともかく、紫本を1週間で読破するぞ!という目標は達成したので、その分問題数をこなせる時間が確保できたのだと思いたい。

やっていきましょう。

徹底攻略 Java SE 8 Silver 問題集[1Z0-808]対応

徹底攻略 Java SE 8 Silver 問題集[1Z0-808]対応

オラクル認定資格教科書 Javaプログラマ Silver SE 8

オラクル認定資格教科書 Javaプログラマ Silver SE 8

関数型インターフェースとラムダ式の練習②

前記事の続き。
こんどは先程利用した関数型インターフェースをラムダ式で書いてみる。
ジェネリクス型は何となく全部Integerにした。

記法は(実装するメソッドの引数) -> {処理};
略記法はまず左辺から。
インターフェース宣言時に引数の型は決定しているため、型推論により型名の省略可。
引数が一つだけなら()も省略可。
引数なしなら()だけ記述。
右辺。
処理が一文なら{}を省略可。{}を省略しているならreturnも省略可。

一部の例だけ略記法を使っていません。

Function<Integer, Integer> obj1 = (Integer num) ->  
        {
	        return num*3;
        };
int result1 = obj1.apply(22);
System.out.println(result1);// 結果:66
Consumer<Integer> obj2 = num -> System.out.println(num+35);
obj2.accept(57);// 結果:92
Predicate<Integer> obj3 = num -> {
	if(num%2 == 0) {
		return true;
	}
	return false;
};
System.out.println(obj3.test(576));// 結果:true
Supplier<Integer> obj4 = () -> 666;
int result2 = obj4.get();
System.out.println(result2);// 結果:666
UnaryOperator<Integer> obj5 = num -> num/6;
int result3 = obj5.apply(5324);
System.out.println(result3);// 結果:887

先ほどと比較して非常にコードが短い。
よかったですね。

関数型インターフェースとラムダ式の練習①

Eclipseでコード書きながら記法の練習してたら可読性0になってしまったので、こっちに清書する。

まずラムダ式に入る前に、主な関数型インターフェースをそのままオーバーライドして利用してみる。完全に使い道を理解してない書き方だが今は仕方がない。
なおジェネリクスの型は適当にStringにしてある。

// Functionインターフェイスのapply()
// String型引数を受け取る。戻り値はString型。
class Func implements Function<String, String>{
	@Override
	public String apply(String t) {
		return "Hello" + t;
	}
}

// 利用先
Func func = new Func();
String funcTest = func.apply("java");
System.out.println(funcTest);// 結果:HelloJava
//Consumerインターフェイスのaccept()
//String型引数を受け取る。戻り値はなし。
class Cons implements Consumer<String>{
	@Override
	public void accept(String t) {
		System.out.println("Hello" + t);	
	}
}

// 利用先
Cons cons = new Cons();
cons.accept("python");// 結果:Hellopython
// Predicateインターフェースのtest()
// String型引数を受け取る。戻り値は真偽値。
class Pred implements Predicate<String>{
	@Override
	public boolean test(String t) {
		if(t.equals("PHP")) {
			return true;
		}
		return false;
	}
}

// 利用先
Pred pred = new Pred();
System.out.println(pred.test("PHP"));// 結果:true
// Supplierインターフェースのget()
// 何も受け取らない。戻り値はString
class Supp implements Supplier<String>{
	@Override
	public String get() {
		return "HelloJavaScript";
	}
}

// 利用先
Supp supp = new Supp();
System.out.println(supp.get());// 結果:HelloJavaScript
//UnaryOperatorインターフェースのapply()
// String型引数を受け取る。戻り値はString
class Unar implements UnaryOperator<String>{
	@Override
	public String apply(String t) {
		return "Hello" + t;
	}
}

// 利用先
Unar unar = new Unar();
String unarTest = unar.apply("Ruby");
System.out.println(unarTest);// 結果:HelloRuby

なんだか長くなりそうなので記事を分ける。

配列、リスト操作に関する一部メソッド

勉強しててちょっと分かりづらかったので書く。

まずarraycopy()について。引数が多くてなんだかごちゃごちゃしてるけど、リファレンスを読めばなんてことはない。例外の送出に注意なのと、コピー先に要素が既にあったとしてもエラーにはならず、コピー元の要素で上書きされる。

int[] array1 = {10, 20, 30, 40, 50};
		
// arraycopy()の利用
int[] copy = {60, 70, 80, 90, 100};
// コピー先の要素数を超えて挿入すると実行時エラー(ArrayIndexOutOfBoundsException)
// System.arraycopy(コピー元の配列名, コピー開始位置, コピー先の配列名, コピー反映位置, コピー数)
System.arraycopy(array1, 0, copy, 0, 4);
for(int val: copy) {
	System.out.print(val + " ");
}
// 結果:10 20 30 40 100

分かりづらかったのはasList()。どうも自分はコレクションが絡んでくると脳がフリーズするらしい。

// asList()の利用
// 引数に指定した配列を固定サイズのリストにして返す
String[] array3 = {"tadokoro", "miura", "kimura"};
List<String> arrayList2 = Arrays.asList(array3);
for(String val: arrayList2) {
	System.out.print(val + " ");
}
結果: tadokoro miura kimura 

// asList()で返されたリストは固定サイズなので、add()で要素を追加すると
// 実行時エラー(UnsupportedOperationException)となる
// 解決方法としては、
// 1.ArrayListクラスのコンストラクタにasList()を渡す
List<String> arrayList3 = new ArrayList<>(Arrays.asList(array3));

// 2.asList()の引数に直接要素を指定する
// ただしasList()はList型で返るため、リストの型もList型にしなければならない
// また要素はObject型でなければいけない
// 下記の場合は引数がint型だが、AutoBoxingでInteger型として扱われるのでエラーは出ない
List<Integer> arrayList4 = Arrays.asList(111, 222, 333);
// 下記はint型の配列を直接引数に渡しているため、コンパイルエラーとなる
// int[] array = {111, 222, 333}:
// List<Integer> arrayList = Arrays.asList(array);

今のところ、苦手な分野については一行一行噛み砕きながらコードを写経していくほかないと思われる。

StringクラスとStringBuilderクラスの文字列比較まとめ

まとめきれてないかもしれんがメモ。

String str1 = "Hello";
String str2 = new String("Hello");
StringBuilder sb1 = new StringBuilder("Hello");
StringBuilder sb2 = new StringBuilder("Hello");

// Stringクラス及びStringBuilderクラスでは
// オブジェクトが保持する文字列を返すという内容でtoStringメソッドが既に実装されている
System.out.println(str1);// Hello
System.out.println(str2);// Hello
System.out.println(sb1);// Hello

System.out.println(str1 == str2);// false…参照値が違う

System.out.println(str1.equals(str2));// true
// Stringクラスではequalsメソッドが既にオーバーライドされており
// 文字列シーケンスが同じならtrueが返る
// よって比較するオブジェクトが両方ともString型の場合のみ、
// 参照値が違っても文字列シーケンスが同じならtrueが返る

//System.out.println(str1 == sb1);// 非互換オペランドでコンパイルエラー

System.out.println(str1 == sb1.toString());// false…参照値が違う

System.out.println(str1.equals(sb1));// false
// ↑引数がStringBuilder型なので文字列シーケンスが同じでもfalseが返る

System.out.println(str1.equals(sb1.toString()));// true
// StringBuilderクラスのオブジェクトが保持している文字列を
// toStringメソッドで一旦Stringオブジェクトとして取り出して比較しているのでtrueが返る

System.out.println(sb1 == sb2);// false…参照値が違う

System.out.println(sb1.equals(sb2));// false
// StringBuilderクラスではequalsメソッドがオーバーライドされておらず
// オブジェクト参照値を比較するため、falseが返る
		
System.out.println(sb1.toString().equals(sb2.toString()));// true
// 前述の通り、StringBuilderクラスのオブジェクトでも一旦toStringメソッドで
// 文字列として比較すればtrueが返る

インスタンスが保持する文字列を比較したいならequalsメソッドを使ってればよくて、StringBuilderクラスならtoStringメソッドで一旦文字列にしないと期待した結果を得られないよという話。
ただ、試験ではひっかけ問題が多い。本来equals()で処理するコードを"=="で書いてて「さあ結果はどうなりますか」っていう嫌がらせを頻繁にしてくるので、取り敢えずまとめてみた。