20170711-1

リファレンスの挙動の確認とか、リフレクションとか。

package sample;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Ref {

	public static void main(String[] args) {
		ref();
	}

	public static void test(String str) {
		str = new String("test");
		System.out.println(str);
	}

	public static void ref() {
		Class<?> clazz;
		try {
			clazz = Class.forName("sample.RefSample");
			Method method = clazz.getMethod("run");
			method.invoke(clazz.newInstance());
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (NoSuchMethodException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
	}
}
package sample;

public class RefSample {
	public void run() {
		System.out.println("RefSample");
	}
}

最頻値を求めるコード

勉強しなくてはいけないことはわかっているのに、何をすべきかはっきりしない。そんな気分でしたので、最頻値を求めるコードを書いてみました。

Mode.java

public class Mode {
	public static Integer mode(List<Integer> list) {
		if (list.size() <= 0) {
			throw new IllegalArgumentException();
		}

		Map<Integer,Integer> modeMap = new HashMap<Integer, Integer>();

		list.stream()
		.forEach(x -> {
			if( modeMap.containsKey(x) ){
				modeMap.put(x, modeMap.get(x)+1);
			} else {
				modeMap.put(x, 1);
			}
		});

		int maxValue = 0;
		int maxKey = 0;

		for (Entry<Integer, Integer> entry : modeMap.entrySet()) {
			if (maxValue < entry.getValue()) {
				maxValue = entry.getValue();
				maxKey = entry.getKey();
			}
		}

		return maxKey;
	}
}

そしてテストクラス

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;

public class ModeTest extends TestCase {

	public void testMode() {
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,6,7,8,9);

		assertEquals(new Integer(6), Mode.mode(list));
	}

	public void testException() {
		List<Integer> list = new ArrayList<Integer>();

		try {
			Mode.mode(list);
			fail("exception is not thrown");
		} catch (IllegalArgumentException e){
			assertTrue(true);
		}
	}
}

別になんてこともないコードではありますが、以前から思っていた「趣味で各コードでもテストクラスを書いたほうがいいよね……」を初めて実行に移せたことが自分の中ではよかったのかなあ、と、いう風に思います。

安易にparallelStreamを使って失敗した話

最近、今更ながらJava8を触っているのですが、
parallelStreamを使うと並列処理ができると聞きまして、
「それならstreamでやったところをparallelStreamに置き換えたら速くなるんじゃん?」
とか安易に考えまして、こんなコードを書いてみました。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


public class Calculate {
	public void run(){
		List<Integer> list = IntStream.range(1, 1000000).boxed().collect(Collectors.toList());

		list.stream()
			.map(x -> x * x)
			.collect(Collectors.toList());

	}
}
// parallelStreamの場合
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class ParallelTest {
	public static void main(String args[]){
		List<Calculate> list = new ArrayList<Calculate>();

		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());

		Date in = new Date();

		list.stream()
			.forEach(x -> x.run());

		Date out = new Date();

		System.out.println(out.getTime() - in.getTime());
	}
}
// streamの場合

import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class StreamTest {
	public static void main(String args[]){
		List<Calculate> list = new ArrayList<Calculate>();

		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());
		list.add(new Calculate());

		Date in = new Date();

		list.stream()
			.forEach(x -> x.run());

		Date out = new Date();

		System.out.println(out.getTime() - in.getTime());
	}
}

1から100000までの値をただただ二乗するメソッドをもつクラスをつくり、
parallelStreamとstreamでそれぞれ実行してみたのですが、
streamでのテストが平均300msほどであったのに対し、parallelStreamは平均3000msほどかかりました。

正直、parallelStreamは並列処理になるので速いはず!
くらいの考えで書いたので、うまくいかないのもしょうがないかなあという気もするんですが、
ネクストアクションはどうしようかな……

「並列処理 Java」とか「parallelStream」で検索してみるかな、とりあえず。

Webサイトの更新情報を自動的に取得するスクリプト【とりあえず完成版】

サイト内にあるファイルの更新情報を取得し、DBに格納するスクリプトです。
すでにそのファイルの更新日時が存在する場合、更新日時を更新。存在しない場合はあらたにinsertする仕様です。

今回からAtomというエディタを使い始めて、かなりコーディングが楽になりました。

※間違いがあったのでこそっと直しました。

<?php

  date_default_timezone_set('Asia/Tokyo');

  $dnsinfo="mysql:dbname=site;host=localhost;charset=utf8";
  $user="siteMaster";
  $pw="site";

  $startDir = "./";

  if(!is_dir($startDir)){
    exit;
  }

  try{
    $pdo = new PDO($dnsinfo,$user,$pw);
    scanningDirectory($pdo,$startDir);
  }catch(PDOException $e){
    echo $e->getMessage();
  }

  function scanningDirectory($pdo,$dir){
    if(is_dir($dir)){
      $dh = opendir($dir);
    }else{
      return;
    }

    while(($file = readdir($dh))!== false){
      if($file == '.' || $file == '..'){
        continue;
      }

      $path = $dir.$file;

      if (is_dir($path)) {
        $path = $path."/";
        scanningDirectory($pdo,$path);
      }else{
        $path = $dir.$file;
        updateDate($pdo,$path);
      }
    }
  }

  function updateDate($pdo,$path){
    $stats = stat($path);
    $updateDate = date('YmdHis',$stats['mtime']);

    $countCheckQuery = "select count(*) from MONITOR_PAGE_TEST where path=?";
    $stmt = $pdo->prepare($countCheckQuery);
    $stmt->execute(array($path));
    while($countCheck = $stmt->fetch(PDO::FETCH_ASSOC)){
      $count = $countCheck['count(*)'];
    }

    if( $count == 1 ){
      $updateQuery = "update MONITOR_PAGE_TEST set update_date = ? where path = ?";
      $stmt = $pdo->prepare($updateQuery);
      $stmt->execute(array($updateDate,$path));
    }else if ($count == 0){
      $insertQuery = "insert into MONITOR_PAGE_TEST values(?,?)";
      $stmt = $pdo->prepare($insertQuery);
      $stmt->execute(array($path,$updateDate));
    }else{
      echo "invalid State of Database.";
    }
  }
?>

ディレクトリにあるファイルの更新日時をテーブルにinsertするスクリプト

 前回の続きです。

 本当はディレクトリを再帰的にたどるようにしたいし、そもそもこのままでは同じファイルの更新日時が既に存在する場合でもupdateではなくinsertしてしまうのでその辺りは修正しなくてはいけませんが、とりあえずこんな感じで作ってみました。

<?php

	date_default_timezone_set('Asia/Tokyo');

	$dnsinfo="mysql:dbname=SITE;host=localhost;charset=utf8";
	$user = "siteMaster";
	$pw = "site";

	$dir = "./";

	if(is_dir($dir)){
		$dh = opendir($dir);
	}else{
		"directory open error \n";
	}

	try{
		$pdo = new PDO($dnsinfo,$user,$pw);
		$query = "insert into MONITOR_PAGE_TEST values(?,?)";
		$stmt = $pdo->prepare($query);

		while(($file = readdir($dh)) !== false){
			$path = $dir.$file;
			$stat = stat($path);

			if(is_file($path)){
				$stmt->execute(array($path,date("YmdHis",$stat['mtime'])));
			}else{

			}
		}
	}catch(PDOException $e){
		echo $e->getMessage();
	}
	
?>

Webサイトの更新情報を自動的に取得するスクリプト【準備の準備編】

Webサイトの更新情報を自動的に取得するスクリプトを書きたいと思っています。

Webサイトにあるすべてのファイルの更新情報をDBに保持

監視

更新されていればその時間をトップページに表示

DB更新

みたいな流れであれば実現できるように思います。

今日はその一歩目として、ファイルの更新時間を取得する方法を調べました。

<?php

	$fileStat = stat("./test.txt");
	echo $fileStat['mtime'];

?>

これだけ!

日経平均株価を取得してDBに格納する【とりあえず完成編】

 前回の続き。

 とりあえずPHPを叩けばDBに日経平均株価をinsertしてくれるスクリプトが出来上がりました。
 cronとかに登録してないので、定期的な取得は出来なくて実質あんまり意味が無かったりしますが……

<?php

	$ch = curl_init("http://stocks.finance.yahoo.co.jp/stocks/detail/?code=998407.O");

	curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
	curl_setopt($ch,CURLOPT_HEADER,false);

	$str = curl_exec($ch);
	curl_close($ch);

	preg_match("/(<td\s*class=\"stoksPrice\"\s*>)(.*?)(<\/td>)/",$str,$result);

	$stocksPrice = floatval(str_replace(",","",$result[2]));

	date_default_timezone_set('Asia/Tokyo');

	$dnsinfo = "mysql:dbname=finance;host=localhost;charset=utf8";
	$user = "FinanceUser";
	$pw = "finance";

	try{
		$pdo = new PDO($dnsinfo,$user,$pw);
		$query = "insert into YAHOO_NIKKEI_STOCK values(?,?)";
		$stmt = $pdo->prepare($query);

		$stmt->execute(array($stocksPrice,date("YmdHis")));
	}catch(PDOException $e){
		echo $e->getMessage();
	}

?>