Java Programmingメモ

提供: Programming-Knowleodge.com
移動先: 案内検索

ここに記載してある内容はJava7までの内容です。


文字列操作

基本

Javaで文字列を扱えるクラスはString, StringBuffer, StringBuilderである。
Stringクラスから生成されたオブジェクトはImmutable(不変)であるのに対して、
StringBufferクラス, StringBuilderクラスから生成されたオブジェクトはMutableなオブジェクトである。
(StringBufferとStringBuilderの違いは、スレッドセーフかセーフではないかの違いがある)


詳細なAPIについては、下記を参照するとよい。

文字コードの変換

文字コードの変換はString strSJIS = new String(str.getBytes(), "<文字コード名>")で行う。
以下がサンプルコードとなる。

String str = "あいうえお";
String strSJIS;
String strEUCJP;
String strWIN31;

try {
	strSJIS = new String(str.getBytes(), "SJIS"); // SJISに変換
	strEUCJP= new String(str.getBytes(), "euc-jp"); // EUC-JPに変換
	strWIN31= new String(str.getBytes(), "Windows-31j"); // Windows-31jに変換
} catch(java.io.UnsupportedEncodingException e) { // getBytesはUnsupportedEncodingExceptionをthrowする
	// 対応していない文字コードでした。
}

System.out.println(System.getProperty("file.encoding"));
				
System.out.println(str);
System.out.println(strSJIS);
System.out.println(strEUCJP);
System.out.println(strWIN31);

getBytesで文字コードを得る上で注意しなければならない点

  • getBytes()を呼び出す時に文字コード名を指定するとと、指定された文字コードで返る。

このとき、指定された文字コードで表現できない文字が含まれていた場合、その文字コードは「?」を意味する「0x3F」を返す。
getBytesについては、下記URLを参照してください。
String (Java Platform SE 8)

  • getBytes()は引数なしで呼び出すと、JVMデフォルトの文字コードが返る。


上記ソースの実行は下記のコマンドで行う

$ java -Dfile.encoding=Windows-31j Test | nkf --utf8

nkfのオプションはターミナル等の表示文字形式で変更すること。

サロゲートペアを扱う

Javaでサロゲートペアを扱うときのメモ

また、一番ためになった、IBMによるサロゲートペアの解説ページへのリンクをメモしておく


サロゲートペアをカウントする

次のようなサロゲートペア文字を含む文字をカウントしたい場合、String#length()ではなく、String#codePointCountを使用する
ただし、サロゲートペアはUnicodeでのみしか発生しないので、他の文字コードの場合は使用しないほうがよい(未検証)
メソッドの詳細はStringを参考のこと。

String str = "あ𠀋𠀋𠀋声"; // 「𠀋」がサロゲートペア

System.out.println(str);

System.out.println(str.length()); // strの長さを表示

System.out.println(str.codePointCount(0, str.length())); // ユニコードのコードポイント(符号点)の数を返す


サロゲートペアを含む文字列から文字を一部取り出す

サロゲートペアが文字列に含まれている場合も、String#substring()を使用するが手順が異なる。
具体的には、String#offsetByCodePoints()を使用してから、切り取りを行う必要がある。
String#offsetByCodePoints()は指定した起点から、コードポイントのオフセット数分離れた位置のインデックスを求めて返す。

String str = "あ𠀋𠀋𠀋い"; // 「𠀋」がサロゲートペア
 
System.out.println(str); // "あ𠀋𠀋𠀋い"
 
// 「あ」を出力する
System.out.println(str.substring(0, str.offsetByCodePoints(0, 1)));
 
// 「𠀋𠀋𠀋い」を出力する
int i = str.offsetByCodePoints(0, 1); 
int j = str.offsetByCodePoints(0, 3 + 2); // +2はstrに含まれる「あ」の分と「い」の分 3+2ではなく、str.codePointCount(0, str.length())); でも良い
System.out.println(str.substring(i, j));

// 「𠀋𠀋𠀋」を出力する
i = str.offsetByCodePoints(0, 1);
j = str.offsetByCodePoints(0, 3 + 1); // + 1はstrに含まれる「あ」の分
System.out.println(str.substring(i, j));

また、このString#offsetByCodePoints()はStringBufferやStringBuilderクラスで、文字列に文字列を追加するときにも必要となる。

サロゲートペアの判定

サロゲートペアの判定は、Character#isSurrogatePair()で行う。
引数で渡せる値はchar型であることに注意が必要である。詳細はCharacterを参照してください。
以下はサロゲートペア判定のサンプルです。

public class Main {
	public static void main(String args[]) {
		System.out.println(Main.containsSurrogatePair("𠀋𠀋え𠀋おい")); // 「𠀋」がサロゲートペア
		System.out.println(Main.containsSurrogatePair("え𠀋𠀋え𠀋おい")); // 「𠀋」がサロゲートペア
	}

	// 指定された文字列にサロゲートペアが含まれているかチェックする 
	public static boolean containsSurrogatePair(String str) {
		char[] c = str.toCharArray();
		int charArrayLen = c.length;
		
		for (int i = 1; i < charArrayLen; i++) {
			if (Character.isSurrogatePair(c[i-1], c[i])) {
				return true;
			}
		}

		return false;
	}
}


正規表現

Matcherクラス及びPatternクラスを使用する方法で、正規表現を行う場合のサンプル

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

// 一部省略

String target = "ABCDEFG-おうえいあ"; // 検索対象文字列
String regex = "^[a-zA-Z0-9 -/:-@\\[-\\`\\{-\\~]+"; // 正規表現パターン 半角英数字と半角記号のみにマッチする

Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(target);

if (true == m.find()) { // 検索対象文字列に正規表現パターンと一致するものが含まれているか
	System.out.println("Match!");
} else {
	System.out.println("Unmactch!");
}


MD5,SHA-1,SHA-256,SHA-512等を使用してハッシュ値を得る

MD5,SHA-1,SHA-256,SHA-512を使用する場合は、java.security.MessageDigestを使います。
基本的な流れは次の通り
1. MessageDigest#getInstanceメソッドでアルゴリズムを得る
2. MessageDigest.updateでハッシュ値を得たい文字列を指定
3. MessageDigest.digestでハッシュ値を取得する(ここで取得できる値はByte型の配列であることに注意)

以下は、MD5を16進数で得るためのサンプルです。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class  MD5Sample {
     public static void main(String args[]) {
          Sample sample = new Sample();
         
          System.out.println(sample.getMD5("testabcdef"));
     }

     public String getMD5(String input) {
          if (input == null) {
               throw new IllegalArgumentException("input string can not be null");
          }

         try {
               MessageDigest digest = MessageDigest.getInstance("MD5"); // 他に"SHA-1, SHA-256, SHA-512が使用できる
         } catch(NoSuchAlgorithmException e) {
               throw new RuntimeException("MessageDigest: not support the Specified algorithm: " + e.toString());
         }
          /* input文字列ををbyteの配列に変換*/
          byte[] inputBytes = input.getBytes(System.getProperty("file.encoding"));
         
          digest.update(inputBytes);

          byte[] digests = digest.digest();
         
          StringBuffer hexStr = new StringBuffer();
          for (int i = 0; i < digests.length; i++) {
               int d = digests[i];
              
               if (d < 0) {
                    d +=256;
               }
              
               if (d < 16) { /* 0〜15は16進数で1桁になるので、2桁になるようにする */
                    hexStr.append("0");
               }
               hexStr.append(Integer.toString(d, 16));
          }

          return hexStr.toString();
     }
}



List, Map, Set, 配列への変換

Listから他のオブジェクトへ変換する

Listから配列へ変換する

List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("123");

// Listから配列にする
String[] arr = list.toArray(new String[list.size()])
for(String item : arr) {
     System.out.println(item);
}


ListからSetに変換

Set<String> set = new HashSet<>();
set.add("123");
set.add("456");
set.add("123");
 
// SetからListへ変換
List<String> list = new ArrayList<>(set);
for(String item : list) {
     System.out.println(item);
}


ListからMapに変換する

配列から他のオブジェクトに変換する

配列からListに変換する

String strs[] = {"123", "345", "123"};
List<String> list = Arrays.asList(array);
// 下記も可
List<String> list = Arrays.asList("123", "345", "123");

オブジェクトの比較とソート

オブジェクトのソート方法について記載する。
ソートには、比較が必須のため、これについても記載する。
ソートの方法は3rd Partyライブラリを使用する方法もある、これについては後述(たぶん書く)する。

オブジェクトの比較

オブジェクトの比較を行う方法は3種類

equalsメソッドはオブジェクトの同値性
比較演算子「==」はオブジェクトの同一性
比較演算子「instanceof」はオブジェクトの型(クラス)の同一性を検証する。
compareToメソッドはオブジェクトの値を大・小・同値か比較するためのメソッドある。
compareメソッドはオブジェクトの値を、大・小・同値かを比較するため外部クラスに実装されるメソッドで、
主にcompareToの実装が変更できない場合などに使用する。(compareメソッドついては後述する)


比較演算子の場合は特に何もすることはない。
equalsメソッドとcompareToメソッドは自分で実装しなければならない。
equalsメソッドはObjectクラスにて実装されているので、自分で定義したクラス内でequalsメソッドをoverrideすればよいが、
compareToメソッドはComparableインタフェースを実装を自分で実装する必要がある。


比較演算子とequalsメソッドの違いについては下記のページがわかりやすい。
JavaにおけるequalsとhashCode - 同一性と同値性の違


以下に、equalsメソッドとComparableインタフェースを実装したクラスの例を示す。(ライブラリにlombokを使用しているので、コンパイルするときは注意)

import lombok.Data;
import java.io.Serializable;
import java.util.Comparator;

@Data
public class PersonDTO implements Comparable<PersonDTO>, Serializable {
	private static final long serialVersionUID = 1L; 
	
	private Integer id; // ID
	private String  name; // 名前
	private Integer age; // 年齢
	
	
	/**
	 * 比較元(this)と比較対象(obj)の大小はID同士の比較により行う
	 * @param obj 比較対象となるPersonDTOのオブジェクトを指定する
	 * @return 比較元が大きいときは、1を返す。比較先が大きいときは、-1を返す。比較元、比較先が同一の場合は、0を返す
	 */
	@Override
	public int compareTo(PersonDTO obj) {
		if (obj == null)
			throw new NullPointerException("null");
 
		if (this.id.compareTo(obj.id) < 0)
			return -1;
		else if (this.id.compareTo(obj.id) > 0) 
			return 1;
		else
			return 0;
	}

	/**
	 * オブジェクトの属性値が同一かどうか比較を行う
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		PersonDTO o = (PersonDTO)obj;
		
		
		return this.id.equals(o.id) && this.name.equals(o.name) && this.age.equals(o.age);
	}
}


上記の例の場合、年齢での比較が行えない。
年齢の比較を行うために、Comparatorインタフェースのcompareメソッドを実装したクラスを次の例を示す。

import java.util.Comparator;

public class PersonDTOAgeComparator implements Comparator<PersonDTO> {
	/**
	 * 比較元(srcObj)と比較先(destObj)の大小はID同士の比較により行う
	 * @param 比較元(o1)となるPersonDTOのオブジェクトを指定する
	 * @param 比較先(o2)となるPersonDTOのオブジェクトを指定する
	 * @return 比較元が大きいときは、1を返す。比較先が大きいときは、-1を返す。比較元、比較先が同一の場合は、0を返す
	 */
	@Override
	public int compare(PersonDTO o1, PersonDTO o2) {
		if (o1 == null || o2 == null) {
			throw new NullPointerException("null");
		}

                
		Integer srcAge, destAge;
 
		srcAge = o1.getAge();
		destAge = o2.getAge();
 
		if (srcAge.compareTo(destAge) < 0)
			return -1;
		else if (srcAge.compareTo(destAge) > 0)
			return 1;
		else
			return 0;
	}
}

ソート

リストやマップに格納されたデータをソートする場合、 リストの場合は、List.sortメソッドまたはjava.util.Collectionsクラスのsortメソッドを使用します。

Listインタフェースを実装したクラスのソート方法

java.utils.Collections#sortメソッドを使用したソート方法

下記にCollectionsを使用したリストオブジェクトのソート方法を示します。ArrayListを使用していますが、Vectorクラス、LinkedListクラスでも同様にソートできます。
ただし、Listに格納するオブジェクトのクラス(下記の例の場合、Integerクラス)がComparableインタフェースを実装している必要があります。

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

public class Main {
	public static void main(String ... args) {
		List<Integer> intList = new ArrayList<Integer>();

		intList.add(new Integer(40));
		intList.add(new Integer(30));
		intList.add(new Integer(10));
		intList.add(new Integer(20));

		System.out.println(intList.toString());

		Collections.sort(intList);

		System.out.println(intList.toString());
	}	
}


実行結果は次のようになる。昇順でソートされます。

> java Main
[40, 30, 10, 20]
[10, 20, 30, 40]


降順でソートする場合は、sortの第二引数に Collections#reverseOrder() を指定します。

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

public class Main {
	public static void main(String ... args) {
		List<Integer> intList = new ArrayList<Integer>();

		intList.add(new Integer(40));
		intList.add(new Integer(30));
		intList.add(new Integer(50));
		intList.add(new Integer(10));
		intList.add(new Integer(20));

		System.out.println(intList.toString());

		Collections.sort(intList, Collections.reverseOrder());

		System.out.println(intList.toString());
	}
}

Mapインタフェースを実装したクラスから作成されたオブジェクトのソート

配列のソート

Arrays.sort (Java Platform SE 8)メソッドを使用する。