「Jasmine」、「Node.js」、「jasmine-node」、「Jenkins」でJavaScriptをテストしてみた。

Javascriptのテストを「Jasmine」を使って実行して、Jenkinsで使ったみたメモです。
動きはしましたがあくまでNode.js用のjavascriptでないと動かないという結果になってしまっています。(方法はあると思いますが。。。)
それでも良い方は続きどうぞ。

また、Karmaを使用したテストではテスト対象のコードをそのまま実行する事ができました。
そのうちこちらもまとめますのでよかったらどうぞ。

目次

以下の順に時系列でダラダラ書いています。

  • Jasmineインストール
  • JavaScriptのコードをJasmineを使ってテスト
  • Node.jsのインストール
  • jasmine-nodeのインストール
  • jenkinsインストール
  • jenkinsでテスト

環境

OS Windows7 Professional 32bit
CPU Core2 Duo 2.93GHz
メモリ 4GB
Jasmine 2.0.0
Node.js v0.10.25
jasmine-node 1.14.3

概要

きっかけ

お仕事で作っているアプリケーションでjsファイルを追加することになったのでテストやってみようって思った。
追加するjsには1つの関数しかないので、スモールスタートとしてはいいかなと。
アプリケーションの規模、用途を考えるとjsファイルが肥大化する事なんて考えられないのでお試しで導入もいいかなと。

今の会社はやりたいと言えば何でもOKだからほんと嬉しいし、楽しい!

Jasmineの選択理由

凄い人に聞いたらJasmineを勧められたため。
(他のフレームワークとの違い、メリットなどはよくわかりません。)

Jasmineとは

JasmineはJavascriptコードをテストするための振舞い駆動開発フレームワークです。他のJavascriptフレームワークに依存しませんし、DOMも必要としません。簡単にテストを書くことができるように、きれいで分かりやすい構文を持っています。

Jasmine: Behavior-Driven JavaScript
種類

2種類あるらしい。

Standalone Release はシンプル、ブラウザページ、コンソールプロジェクト用です。
Jasmine Ruby Gem は、Rails, Ruby, or Rubyに慣れている開発者用です。
他の環境も同様にサポートされます。

Jasmine: Behavior-Driven JavaScript

私はRubyとは縁遠い上に、特に高機能である必要はないのでStandalone Releaseを使用しました。

準備

モジュール取得

さっきからリンクを張っている日本語訳のページだとダウンロードページのリンクがおかしいので、公式のここの一番下の「Downloads」からダウンロードページに飛びます。
で、どうせなら最新版ということで「jasmine-standalone-2.0.0.zip」を落としました。

解凍

取得したモジュールを解凍

JASMINE-STANDALONE-2.0.0
├MIT.LICENSE
├SpecRunner.html
├lib
│└jasmine-2.0.0
│  ├boot.js
│  ├console.js
│  ├jasmine-html.js
│  ├jasmine.css
│  ├jasmine.js
│  └jasmine_favicon.png
├spec
│├PlayerSpec.js
│└SpecHelper.js
└src
  ├Player.js
  └Song.js
  • SpecRunner.html : これを開いた時にテストが実行されて、結果が表示されます。
  • lib/jasmine-2.0.0配下 : Jasmine本体
  • spec配下 : テストファイル
  • src配下 : テスト対象のファイル

本体のみかと思ったらサンプル一式入ってました。

Jasmine実行

サンプル実行

↑でも書きましたが、SpecRunner.htmlを開いたら実行されて結果が表示されます。
5個のテストケースを実行して失敗は0件と表示されているはず。
当然テストは全部成功していますし、テストコードもテスト対象のコードも見てないので正直よくわからない。

実践

サンプルを見てみたらなんとなくわかったけど、サンプル内で文字列比較とかないので失敗のケース作るのがめんどくさい。
なので、いきなりコード書いて、試してみる。

  • テスト対象コード
function Hoge(a,b) {
  return a + b
}
  • テストコード
    • ファイル名に「spec.js」をつける必要あり。
describe("Hogeクラス", function() {
  it("数字足し算", function() {
    expect(Hoge(1,2)).toEqual(3);
  });
  it("文字列足し算", function() {
    expect(Hoge("a","b")).toEqual("ab");
  });
  it("テスト失敗", function() {
    expect(Hoge(1,2)).toEqual(5);
  });
});
  • SpecRunner.htmlをコピーしてテスト対象とテストコードを追加。
<!DOCTYPE HTML>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Jasmine Spec Runner v2.0.0</title>

  <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css">

  <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script>
  <script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script>
  <script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script>

  <!-- include source files here... -->
  <script type="text/javascript" src="src/Player.js"></script>
  <script type="text/javascript" src="src/Song.js"></script>

  <!-- include spec files here... -->
  <script type="text/javascript" src="spec/SpecHelper.js"></script>
  <script type="text/javascript" src="spec/PlayerSpec.js"></script>

  <!-- 追加メインコード -->
  <script type="text/javascript" src="src/Sample.js"></script>

  <!-- 追加テストコード -->
  <script type="text/javascript" src="spec/SampleSpec.js"></script>
</head>
<body>
</body>
</html>

で、適切な場所に保存してSpecRunner.htmlをコピーしたファイルを開くといい感じの結果。

結果画面

どうやらこんな感じらしい。

  • 一番上はバージョン。
  • 一番上の右に実行時間表示(テスト実行に時間がかかる場合には実行中とかは出ない。。。)
  • 緑の●は成功で赤の×は失敗。
    • 数を増やしたら単純に増えただけだった。。。
  • バーが赤くなっていたら失敗しているテストケースがある
  • Spec Listをクリックすると成功時と同じテストケース一覧を表示
  • 最下部はテスト失敗時のスタックトレースを表示

Jenkinsとの連携(前書)

ユニットテストはJenkinsで行っているため、htmlでテスト出来てもしょうがない。
ということで、JasmineをJenkinsで動かすための手順を調べてました。

  • JavaScriptなので、JavaScriptを動作させるエンジンが必要。
  • で、ブラウザ、Node.js、PhantomJSなどがある。
    • これらの環境で動作させるためにkarma、jasmine-nodeなどを使用する。(Node.jsの場合は直で動かすことができそうだけど、そう簡単にいかないのかしら?)
  • Jenkinsにプラグイン入れてPATH指定したらできるんじゃないか。とか簡単に考えてたけど結構大変っぽい。
  • 手間は手間だけど、こういうのは最初作っちゃえばなんとかなるさということで作る。
  • ブラウザは起動が遅い上にバージョンとかに依存しそう、という事でボツ。
  • Node.jsは少し触ったことがあって、他は全く知らないのでjasmine-nodeを使用してNode.js上で動作させる事に決定。

node.jsインストール

Node.js
私はWindowsなので、「Install」クリックしてインストーラでインストール。
「ダウンロード」からexeも落とせますが、インストーラの方がいいとどっかで見た気がするので大人しくインストーラ実行。
インストールできたらコマンドプロンプト開いてバージョン確認。

$ node -v
v0.10.25

jasmine-nodeインストール

JasmineのテストをNode.jsで動作させるために「jasmine-node」をインストール。

npm install -g jasmine-node

npmはNode.jsのパッケージ管理ツールで、「node.exe」と同じPATHにあるのでNode.jsのバージョン表示されていれば動作するはず。
インストールできたらコマンドプロンプト開いてバージョン確認。

$ jasmine-node  --version
1.14.3

jasmine-nodeでテスト実行

とりあえず実行

早速↑で作ったコードを動かしてみる。

$ jasmine-node ./spec/SampleSpec.js
FFF

Failures:

  1) Hogeクラス 数字足し算
   Message:
     ReferenceError: Hoge is not defined
   Stacktrace:
     ReferenceError: Hoge is not defined
    at null.<anonymous> (c:\work\20140424\gomi\spec\SampleSpec.js:5:12)

  2) Hogeクラス 文字列足し算
   Message:
     ReferenceError: Hoge is not defined
   Stacktrace:
     ReferenceError: Hoge is not defined
    at null.<anonymous> (c:\work\20140424\gomi\spec\SampleSpec.js:8:12)

  3) Hogeクラス テスト失敗
   Message:
     ReferenceError: Hoge is not defined
   Stacktrace:
     ReferenceError: Hoge is not defined
    at null.<anonymous> (c:\work\20140424\gomi\spec\SampleSpec.js:11:12)

Finished in 0.024 seconds
3 tests, 3 assertions, 3 failures, 0 skipped

っということでテストする関数がないよって事で失敗。(1行目に出力されている「FFF」はHTMLでいう●らしい。)
そりゃ、テスト対象のjsを指定してないので当たり前。
Node.jsの機能?でexports、requireがあるので、これを行うことで紐付けます。

  • テスト対象クラス
function Hoge(a,b) {
  return a + b
}

exports.Hoge = Hoge;
  • テストクラス
    • requireで指定するファイルPATHはテストクラスからの相対PATHです。(ここで設定するとわかるけど、jenkinsに設定後だとworkspaceからと勘違いしてしまったので一応。)
var Hoge = require('../src/Sample.js').Hoge;

describe("Hogeクラス", function() {
  it("数字足し算", function() {
    expect(Hoge(1,2)).toEqual(3);
  });
  it("文字列足し算", function() {
    expect(Hoge("a","b")).toEqual("ab");
  });
  it("テスト失敗", function() {
    expect(Hoge(1,2)).toEqual(5);
  });
});
再実行

上記の設定後に再実行。

$ jasmine-node ./spec/SampleSpec.js
..F

Failures:

  1) Hogeクラス テスト失敗
   Message:
     Expected 3 to equal 5.
   Stacktrace:
     Error: Expected 3 to equal 5.
    at null.<anonymous> (c:\work\20140424\gomi\spec\SampleSpec.js:11:23)

Finished in 0.076 seconds
3 tests, 3 assertions, 1 failure, 0 skipped

正しく実行されて、1件のテスト失敗がわかります。

Jenkinsインストール & 起動

いきなり動いているJenkinsでやるのもどうかと思うのでローカルにJenkins導入。

Jenkins設定

Job作成
  • 新規ジョブ作成
  • ジョブ名適当に入力
  • 「フリースタイル・プロジェクトのビルド」選択
  • OK
設定といきたいけどファイル配置

本来はバージョン管理システムから取得する所だけど、この段階ではそんなものないので手動でworkspaceに配置。

  • 私の環境だと↓
    • 「C:\Users\${ユーザ名}\.jenkins\jobs\${ジョブ名}\workspace\」
  • 私は以下のように配置しました。
C:\Users\${ユーザ名}\.jenkins\jobs\${ジョブ名}\workspace
└test
  ├lib
  │└jasmine-2.0.0
  │  ├boot.js
  │  ├console.js
  │  ├jasmine-html.js
  │  ├jasmine.css
  │  ├jasmine.js
  │  └jasmine_favicon.png
  ├spec
  │└SampleSpec.js
  └src
    └Sample.js
ジョブの設定 & 実行
  • ビルド部の「ビルド手順の追加」
  • Windowsバッチコマンドの実行」を追加
  • コマンド
jasmine-node test\spec\SampleSpec.js
  • 保存
  • ビルド実行
  • 以下の感じで出力されればOK(日本語が化けているのは気にしない。。。)
ユーザーanonymousが実行
ビルドします。 ワークスペース: C:\Users\yamap\.jenkins\jobs\Sample\workspace
[workspace] $ cmd /c call C:\Users\YAMAP\AppData\Local\Temp\hudson5171352823916894994.bat

C:\Users\yamap\.jenkins\jobs\Sample\workspace>jasmine-node test\spec\SampleSpec.js 
..F

Failures:

  1) Hoge繧ッ繝ゥ繧ケ 繝&#65533;繧ケ繝亥、ア謨&#65533;
   Message:
     Expected 3 to equal 5.
   Stacktrace:
     Error: Expected 3 to equal 5.
    at null.<anonymous> (C:\Users\yamap\.jenkins\jobs\Sample\workspace\test\spec\SampleSpec.js:15:23)

Finished in 0.022 seconds
3 tests, 3 assertions, 1 failure, 0 skipped


Build step 'Windowsバッチコマンドの実行' marked build as failure
Finished: FAILURE
レポート出力

コンソールに出力されてもどうしようもないのでJUnit形式でレポート出力を行う。

  • 設定変更
    • コマンド
jasmine-node test\spec\SampleSpec.js --junitreport --output "reports"
    • ビルド後の処理に「JUnitテスト結果の集計」を追加
reports\*
  • 保存
  • ジョブ実行(相変わらずコンソール上では日本語が化ける。。。)
ユーザーanonymousが実行
ビルドします。 ワークスペース: C:\Users\yamap\.jenkins\jobs\Sample\workspace
[workspace] $ cmd /c call C:\Users\YAMASH~1\AppData\Local\Temp\hudson941930116661068781.bat
C:\Users\yamap\.jenkins\jobs\Sample\workspace>jasmine-node test\spec\SampleSpec.js --junitreport --output "reports" 
..F

Failures:

  1) Hoge繧ッ繝ゥ繧ケ 繝&#65533;繧ケ繝亥、ア謨&#65533;
   Message:
     Expected 3 to equal 5.
   Stacktrace:
     Error: Expected 3 to equal 5.
    at null.<anonymous> (C:\Users\yamap\.jenkins\jobs\Sample\workspace\test\spec\SampleSpec.js:11:23)

Finished in 0.028 seconds
3 tests, 3 assertions, 1 failure, 0 skipped


Build step 'Windowsバッチコマンドの実行' marked build as failure
テスト結果を保存中
Finished: FAILURE
  • テスト結果が出力されていればOK

問題

  • Jenkinsのコンソール上で日本語を正しく表示させたい(レポートは化けてないので別に問題はないですが。)
    • 以前別のプラグインでハマったんだけど解決策は忘れたw
  • そもそもテスト対象コードに手を入れたくない。
    • Node.js以外の環境だとexportsメソッドが定義されていないので動かない。(jasmine付属のHTMLでの実行も同じ理由でNG。)
    • 色々試したけどNode.jsで動作させるのでexportは書く必要があるっぽい(別のファイルから指定できると思うけど方法がみつからず。)

GebのグループIDは0.9.0で変更されている

GebのグループIDは0.9.0で以下のように変更されています。(2014/04/17時点での最新版は0.9.2)

  • 新グループID
    • org.gebish
  • 旧グループID

リリースノートがどこにあるのかわかりませんでしたが、0.9.0のマニュアルの記述が変更されています。

dependencies {
    test "org.gebish:geb-spock:0.9.0"
}
plugins {
    test ":spock:0.7"
    test ":geb:0.9.0"
}
dependencies {
    test "org.codehaus.geb:geb-spock:0.7.2"
}
plugins {
    test ":spock:0.5-groovy-1.7"
    test ":geb:0.7.2"
}

Gebは参考にする記事が少ない事もあって、大体の記事では「org.codehaus.geb」と書いてあります。
これから触る方は注意が必要!!
selectが実用的じゃない位遅いし。。。

Mapの初期化でKeyをGStringにした場合、getメソッドを使用しないと値を取得できない。

表題の通り。
Mapの初期化時には変数名を直接指定できないので、GStringで対応していたらハマった。

  • っというか、元々はcollectEntriesイジっててハマったのでcollectEntriesがおかしいって記事まで書いてた。。。

環境

$ groovy -version
Groovy Version: 2.2.2 JVM: 1.8.0 Vendor: Oracle Corporation OS: Windows 7
  • 2.3.0-beta-2でも発生しました。

現象

言葉で説明は下手くそなのでコードで。

def key1 = "a"

// 変数は直接指定できない(文字列のKeyとして処理される)
def map1 = [key1:"a"]
assert map1 == ["key1":"a"]

// GStringは別のKeyとして認識される
def map2 = ["${key1}":"a"]
assert map2 != ["a":"a"]
assert map2 == ["${'a'}":"a"]
assert map2.keySet()[0].class == org.codehaus.groovy.runtime.GStringImpl

// StringとGStringの型
def key2 = "${key1}"
assert key1.class == java.lang.String
assert key2.class == org.codehaus.groovy.runtime.GStringImpl

// containsKeyはGStringで格納されているとの事。
assert !map2.containsKey(key1)
assert map2.containsKey(key2)

// StringでもGStringでも取得できない
assert map2[(key1)] == null
assert map2[(key2)] == null
assert map2.(key1) == null
assert map2.(key2) == null

// 直接getメソッドを呼ぶと取得が可能
assert map2.get("a") == null
assert map2.get("${'a'}") == "a"

つまり、GStringを使用してMapを初期化するとStringではなくてGStringとして格納されるため、Stringで取得しようとしてもダメ。
では、GStringで指定しても[]の呼び出しは(getAtメソッド)Groovyがいい感じにStringに変換してくれているようなのでこれもダメ。
Javaメソッドのgetを直接呼ぶことでGStringをそのまま渡せるので習得ができます。

初期化以外の処理では、GStringはStringに変換されて格納されるため、格納時にも取得時にも問題は発生しません。

def key1 = "a"
def key2 = "${key1}"
// 初期化以外では変数はそのまま指定可能
// GStringもStringに変換されて格納される。
def map3 = [:]
map3[key1] = "a"
map3[key2] = "b"
assert map3.size() == 1
assert map3[key1] == "b"
assert map3[key2] == "b"
assert map3.keySet()[0].class == java.lang.String
assert map3.get(key1) == "b"
assert map3.get(key2) == null

正直この挙動はどうなんでしょう。。。?

回避策

変数使いたいだけなら()を使用する事で回避可能。
文字列の結合が必要ならば「as String」でStringに変換する。

def key1 = "a"
def map4 = [(key1):"a"]
assert map4 == ["a":"a"]
assert map4 != ["${'a'}":"a"]
assert map4[key1] == "a"
assert map4[key2] == "a"

def map5 = [("${key1}_${key2}" as String):"a"]
assert map5 == ["a_a":"a"]
assert map5 != ["${'a_a'}":"a"]
assert map5["a_a"] == "a"
assert map5["${'a_a'}"] == "a"

参考

ここまで色々回り道して調べたんですが、下書き書いてからもう一回ググったらふもさん(id:fumokmm)のblogが出てきた。
5年前に調べてくれてるじゃないですかーやだー
しかも、id:uehajさんがJIRAまで調べてくれてるじゃないですかー

Groovyでマップのキーに文字列を指定する際の注意点 - No Programming, No Life

5年前でなおってないなら仕様ですね。
これわかりづらいと思うんですが。。。

GebでSelect要素の選択が遅い

追記(2014/04/17)

解決しました。
id:kyon_mmさんがコメントで指摘くださいました。
0.9.0で修正されているらしいのでバージョンを上げればよし。
具体的には「@Grab("org.codehaus.geb:geb-core:*")」を「@Grab("org.gebish:geb-core:0.9.2")」と変更すればOK。
詳しくは別記事にも書いたので興味のある方は↓

概要

SeleniumのGroovyのラッパーであるGebを使っていたのですが、Select要素を設定すると物凄く遅い。
っというか、使い物にならないくらい遅い!!
下記のコードを実行すると、Seleniumを直で使用した場合は500ミリ秒程度ですが、Gebの方は8000ミリ秒程度もかかります。

環境
OS Windows7 Professional 32bit
CPU Core2 Duo 2.93GHz
メモリ 4GB
Groovy Version 2.2.2
Java Version 1.8.0
firefox 27.0.1
HTML
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <select id="year">
    <option value='-'>-</option>
    <option value='1900'>1900</option>
    <option value='1901'>1901</option>
<-- 中略 -->
    <option value='2013'>2013</option>
    <option value='2014'>2014</option>
  </select>
  <select id="month">
    <option value='-'>-</option>
    <option value='01'>01</option>
    <option value='02'>02</option>
<-- 中略 -->
    <option value='11'>11</option>
    <option value='12'>12</option>
  </select>
  <select id="day">
    <option value='-'>-</option>
    <option value='01'>01</option>
    <option value='02'>02</option>
<-- 中略 -->
    <option value='30'>30</option>
    <option value='31'>31</option>
  </select>
</body>
</html>
コード
@Grapes([
     @Grab("org.seleniumhq.selenium:selenium-java:*"),
     @Grab("org.seleniumhq.selenium:selenium-support:*"),
     @Grab("org.seleniumhq.selenium:selenium-firefox-driver:*"),
     @Grab("org.codehaus.geb:geb-core:*"),
])
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.By
import org.openqa.selenium.support.ui.Select

import geb.Browser
import geb.Configuration

println "start"
def driver = new FirefoxDriver()
driver.get("http://jsbin.com/sucumuqu/2/")
def now = new Date()
def year = new Select(driver.findElement(By.id("year")))
year.selectByVisibleText("1950")
def month = new Select(driver.findElement(By.id("month")))
month.selectByVisibleText("08")
def day = new Select(driver.findElement(By.id("day")))
day.selectByVisibleText("15")
println "${new Date().time - now.time}"
driver.quit();

Configuration conf = new Configuration()
conf.baseUrl = "."
conf.driver = new FirefoxDriver()
Browser.drive(conf) {
  go "http://jsbin.com/sucumuqu/2/"
  now = new Date()
  $("#year").value("1950")
  $("#month").value("08")
  $("#day").value("15")
  println "${new Date().time - now.time}"
  quit()
}

println "end"

しょうがないので、driverを取得して直接操作するとほぼ同じ時間で処理が完了する。(当たり前)

@Grapes([
     @Grab("org.seleniumhq.selenium:selenium-java:*"),
     @Grab("org.seleniumhq.selenium:selenium-support:*"),
     @Grab("org.seleniumhq.selenium:selenium-firefox-driver:*"),
     @Grab("org.codehaus.geb:geb-core:*"),
])
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.By
import org.openqa.selenium.support.ui.Select

import geb.Browser
import geb.Configuration

println "start"
def driver1 = new FirefoxDriver()
driver1.get("http://jsbin.com/sucumuqu/2/")
def now = new Date()
def year = new Select(driver1.findElement(By.id("year")))
year.selectByVisibleText("1950")
def month = new Select(driver1.findElement(By.id("month")))
month.selectByVisibleText("08")
def day = new Select(driver1.findElement(By.id("day")))
day.selectByVisibleText("15")
println "${new Date().time - now.time}"
driver1.quit();

Configuration conf = new Configuration()
conf.baseUrl = "."
conf.driver = new FirefoxDriver()
Browser.drive(conf) {
  go "http://jsbin.com/sucumuqu/2/"
  now = new Date()
  year = new Select(driver.findElement(By.id("year")));
  year.selectByVisibleText("1950");
  month = new Select(driver.findElement(By.id("month")));
  month.selectByVisibleText("08");
  day = new Select(driver.findElement(By.id("day")));
  day.selectByVisibleText("15");
  println "${new Date().time - now.time}"
  quit()
}

println "end"

セレクタが遅い?ただ、テキストボックスやラジオだとそこまで遅いとは感じないのでセレクトボックス特有の原因かな?
ソース読めっていう話なんだけど。。。

「祝☆Java 8 Launch」に行ってきた #JJUG

3/18にリリースされたJava SE 8を勉強するためにJJUGの勉強会に参加してきました。

何回かOracleに来てますが、2部屋ぶちぬきでしかもテーブルなしというのははじめてでした。
っと思ったら、MAX300人はOracle初だったらしいです。

最初にまとめ

メモが長くなってしまったので、最初にまとめ。

  • Lambdaは凄い。
    • 簡潔に書ける(場合もある
    • 最初は読みにくいかもだけど、慣れる
    • forやwhileをみたらStream APIへの置換えを考える。
  • 既存のAPI、処理もパフォーマンス向上!
  • メモリの使用量も低下。
  • JavaFX8もパフォーマンス向上!

Java SE 8 正式リリース

13:00〜13:30 祝 Java SE 8 正式リリース

寺田 佳央(@yoshioterada) 日本オラクル Java エバンジェリスト

2011 年 7 月に Java SE 7 がリリースされ、ついにJava SE 8 が正式にリリースされました。Java SE 8 では目玉機能である Project Lambda の他、JavaFX の統合、新規 JavaScript エンジンの提供など、50 を超える機能が追加もしくは改善されています。
本セッションは Java SE 8 の概要をわかりやすくご紹介します。
  • テクニカルの話はない。
  • 今日の話で出てこない話をする。
  • 135枚のスライドは全部紹介できないので、blogに書くのでそっちを見てくれ。
  • JavaSE 7を出す時に全部ひっくるめて出すか、段階的にリリースしていくか。
  • 段階的にリリースしていくことに決定。
  • SE7 2011年7月28日リリース
  • 会場にいる方の現在使用Javaバージョンの調査。
    • 7が圧倒的。
    • 1.4の人も何人か。
  • 2012年7月17日
    • JigsawはJavaSE9へ持ち越し。
  • 2013の年始から中旬までOracleのトップ判断で、セキュリティ脆弱性対応に集中。
  • スケジュールをずらしても構わないとの事。
  • 2014年4月26日
    • 2014/03/18にリリース決定。
  • JSR-337 : Java SE8
  • JavaSE8にすることのメリットは多くある。
  • クラスファイルのフォーマットなども変わってる。
  • パフォーマンスを上げるための機能、既存のライブラリにも修正が。
  • メモリの使用量も減っているらしい。
  • 新機能を使用しなくても、メリットはたくさんある。
  • Compactプロファイル。(ファイルサイズが異る。)
  • APIにどのプロファイルで利用可能か記載されている。
  • 参考資料
    • JavaSE8のリリースノート
      • 機能以外のJDK8のサポートする環境も乗っていたりする
    • JDKの新機能概要
    • Java Platform Standard Edition8ドキュメント
    • JDK8の互換性・非互換性の情報ガイド(コンパチビリティーガイド?
    • Java7 からJava8 に変わって、何が変わったのか。
    • Java7 ではワーニングだったものがコンパイルが通るようになったりしているらしい。
    • デフォ値がfalseだったのがtrueになったとかもあるらしい。(過去のSwingの話
  • Java7のサポートも来年4月に変わっている。
今後のJava関連イベント

5月のJava祭り

まとめ

新機能だけじゃなくて、色々加わってる。
楽になってるし、早くもなっている。

徹底解説!Project Lambdaのすべて リターンズ

13:30〜14:20 徹底解説!Project Lambdaのすべて リターンズ

発表者:吉田 真也(@bitter_fox) 立命館大学 立命館コンピュータクラブ

Java 8 における最大級のプロジェクトであるProject Lambda で導入された言語特徴のすべてを解説します。また、Project Lambda で導入されたStream API も解説します。
なぜその特徴を導入しなければいけないかや他の特徴とどのように関連しているのかについても説明しますので、より広い視野でProject Lambda を理解することができます。
Project Lambda のそれぞれの特徴と全体像を理解できるセッションです。
  • Lambdaの開発者にツッコミを入れたりしてるらしい。
  • 大学生。立命館大学
  • アップデートには2種類ある
    • エボリューション
    • レボリューション
    • 日本語的には進化と革命
  • Jdk5以来、レボリューションは10年ぶり2004年ぶり。
  • ラムダは、並列処理を容易に書けるように増強。
    • ライブラリ、言語
    • マルチコアCPU
    • クロック数はそのまま、コア数を増やす。並列処理。
    • 並列プログラミングをしないと、性能を活かすことが出来ない。
  • 並列処理
  • Java5で大きな粒度 簡単
    • Java7で小さな粒度 やや難
  • 処理を分けるだけで5行(匿名クラスを使用)
    • 言語的に解決する必要がある。
  • ライブラリの増強
  • 全体像、ラムダの全体で7個。
ラムダ式・メソッド参照
実質的にfinal
  • 匿名クラスはfinalの変数しかアクセスできなかった。
  • コンパイラが変数が変更されるか判断するので、final修飾子がなくてもアクセス可能。
  • よって、ラムダ式内で値を変更したり、ラムダの後で値を変更したりするとコンパイルエラー
型推論の強化
  • ターゲット型推論の強化
  • ターゲット型に基づく型推論
  • 有ある式の方として予期される型のこと
交差型キャスト
  • キャスト式に交差型を。
  • T extends
  • 型合成される
  • ぶっちゃけ使わないwww
    • APIでも使用してるクラスは5個
デフォルト実装
staticインターフェイスメソッド

コアライブラリ
  • StreamAPI
  • Optional
  • JCF
  • IO
  • And more
  • StreamAPI
  • イテレーションが外に晒されている
    • for,while文
  • StremAPI
    • 並列化が簡単に行える。
  • java.util.stream
    • ソースから生成される。
    • 中間操作と終端操作でデータを弄る。
    • 並列化が容易
IntStream.rangeClose(0,10).forEach(i -> System.out.println(i));
// 偶数のみ表示
IntStream.rangeClose(0,10).filter(i->i%2==0).forEach(...)
// Personのリストから名前を出力
// map
persons.stream().map(p-> p.getName()).forEach(....)
// Personのリストから名前のリスト
persons.stream().map(Person::getName).collect(p-> )
まとめ
  • 元々はマルチコア対応
  • 結果としては汎用的な仕様に
  • よりスマートなコードへ

null書いたら負け!Java8コーディング作法

14:30〜15:20 null書いたら負け!Java8コーディング作法

発表者:きしだ なおき(@kis)

負けだよ。
  • null書いたら負け!
  • Streamはコーディング規約で禁止でもいい
  • Date and Timeはよくわからない

だが、nullお前だけはダメ。

  • java.util.Optional
  • 値を持つか持たないかを判別。
  • nullのある世界とない世界の分離
  • nullを使っていいところ悪いところ
  • 良い
    • ローカル変数
  • 微妙
    • 引数
  • 悪い
    • フィールド
    • 戻り値
  • nullを外に漏らさなければOK
覚えて欲しいのは

nullを返すメソッドを書いたら負け。

Java8の他の作法
  • Streamでの注意
  • メソッド参照とラムダの使い分け
  • 遅延実行を活かす
  • Mapを活用する
  • 制御構造を自作する
  • Streamでの注意
    • 副作用に気をつける
    • メソッドの中でメソッドの外に影響を与えない
  • 副作用を使う基準
    • 中間操作×
    • 終端操作
      • reduce △
      • forEach ○
  • 遅延実行を活かす
    • 値が使われる可能性の低い引数の構築に時間がかかる時
logger.debug(bigObject.toString());
logger.fine(()->bigObject.toString());
    • Optional
      • Optional#orElseGet
      • Optional#orElseThrow
      • 使う可能性が低い時はラムダにしとけば、使うときにのみ実行してくれる?
  • Mapを活用する
    • Map>
  • 追加
    • Map#computelfAbsent
    • Mapが空だった時にその値を突っ込んで返してくれる?
  • 削除
    • Map#computerlfPresent
  • メモ化
    • Map#computelfAbsent
    • 値があればその値、なければ計算を行って結果をMapに格納しつつ返す。
  • 制御構造を自作する
    • カスタムwith
    • カスタム分岐
    • カスタムマッチ
    • カスタムループ
  • メソッド参照とラムダの使い分け
    • メソッド参照は引数を隠す。
    • 読み解くにはコンテキスト理解が必要。
  • メソッドに渡すためのメソッド○
  • 引数一つのメソッド△
  • 引数複数のメソッド×

Brand new Date and Time API

15:30〜16:20 Brand new Date and Time API

発表者:蓮沼 賢志(@khasunuma) JSR 310 オブザーバー

Java Community Process (JCP) では、2007 年から Java の日付と時刻の扱いを改善する JSR 310 “Date and Time API” を開始し、7 年の歳月を経て Java SE 8 の標準 API として結実しました。これまでの Date や Calendar とは全く異なる思想で開発された最新の日付・時刻 API を今日から活用して頂けるよう、このセッションがお手伝いを致します。
  • 日付と時刻のAPI
  • ISO8601
  • UNIXタイムと異なる概念
  • 日付とは何。
  • 日付とは秒が基準。
  • java.time, java.time.format, java.time.chronoパッケージでだいたいおk
  • isBefore
  • isEqualsとかもある。

JavaFXGUI by Illusion

16:30〜17:20 JavaFX &#8211; GUI by Illusion

発表者:櫻庭 祐一(@skrb) Java in the Box

Java SE 8 では、Swing に代わり JavaFX が標準の GUI ライブラリとなります。
JavaFX は、XML で GUI の構造を記述し、CSS で見た目を、Java でロジックを記述するようになります。また、組み込みブラウザやチャートなど多くの機能が提供されています。
本セッションでは、JavaFX の基本から、Swing からのマイグレーション、JavaFX 8の新機能などを、デモを交えて紹介します。
  • 今までJavaに無かったエフェクトを入れるよということでJavaFX
    • "%jre%\lib\calendars.properties"に和暦とかを追加することができる。
  • JavaFXって何
  • Swingからの移行
  • JavaFX 8の新機能
  • JavaFXって何
    • JavaSEの新しいGUIライブラリ
    • Swing + java2D + JavaMediaFW + α
    • FXMLとCSSJavaで書く。
    • FXML - ControllerClass - Model
  • SceanBuilder
  • EclipseはeFXclipseで連携できるらしい。
  • Browser
  • 3行
WebView view=new WebView();
WebEngine engine = view.getEngine();
engine.load("http://www.google.com");
  • Media
    • 標準的な形式は大体動く
  • Effect
    • 一通りできる
  • Animation
    • 当たり前のように動く
  • Touch Gesture
    • 1行で回転!1行でズーム!
  • robovmっというの使えばIOSで動作するように変換できるらしい。
  • Swingからの移行
    • 構造は殆ど同じ、
    • ただ、FXMLでかけるよ!
    • 各クラスに関してもJを除いたり、似た名前であります。
    • 属性とかも殆どそのまま使える。
    • TableやTreeに関しては考え方が変わってるので鬼門になるかも。
  • JavaFX8
    • 色々変わってる
    • パフォーマンスが格段にアップ!
    • 3D
    • 印刷が使えるように(今まで何故なかったw
    • テーマ(CSSでアプリケーション全体の見た目を変えることができる。
    • DatePicker(LocalDateが取れる。
    • JavaFXの中でSwingやSWTを動かす事ができるようになった。
    • 非同期処理を簡単に書けるようになった
    • ショートカットキーでフルスクリーンにする事ができるようになった
    • とかとか。。。
  • 3Dを簡単に説明
  • FXは新しいGUIライブラリなんだよ
  • FXML-CSS-Javaで書ける
  • いろいろ新しいのが入ったよ。
  • Swingから簡単に移行できるよ。
  • JavaFX8は色々すごいよ!
  • OpenJDKでも動く。

from old Java to modern Java – reloaded

17:30〜18:20 from old Java to modern Java &#8211; reloaded

発表者:谷本 心(@cero_t) Acroquest Technology

Java SE 8がリリースされるというニュースを目にしても「どうせ仕事では使えないし」と冷ややかに見ていませんか?
確かに開発の現場では、様々な制約のために古いバージョンのJavaを使わざるを得ないことがあります。しかしだからと言って学ばないままでいると、いざ新しいバージョンのJavaを使おうという時に、ついつい古いAPIを使ってしまったり、古い慣習に従って書いてしまうことになるでしょう。
このセッションでは、JavaのAPIや慣習について、古い時代のものからJava8までの歴史を振り返りながら、イマドキの書き方を紹介します。
  • 仕事でJava8を使おうと思った時に何を気をつければいいのか。
  • 老害にならないためのJava8入門。
    • ラムダで欠かれたコードをレビューした時に読みにくいと言わないように勉強しなければならない。
  • finallyでCloseするのは古い定石(〜Java6
  • tryの中で開く。(〜Java7
  • FilesとかPathクラスとか使わないとダメだよね。
  • try-with-resourcesとFilesとPathで操作する。(Java7〜
Files.lines(Paths.get(fileName)).forEach(s-> lines.add("<" + s + ">"));
  • forやwhileをみたらStream APIへの置換えを考える。
  • ラムダでmapとcollectはよく使う。(Streamはここから始める)
  • 何でもかんでもLambdaにすればいいわけじゃない。
  • 「ラムダ禁止」でググる
    • ラムダのAPIをもっと便利に使うことができる。
まとめ

自分たちの標準としてどうすれば読みやすくするかチームで考えよう!
Java本格入門(仮)鋭意執筆中!

Raspberry Pi on Java ショートアップデート

18:20〜18:30 Raspberry Pi on Java ショートアップデート

発表者:太田 昌文(@masafumiohta) Japanese Raspberry Pi Users Group

昨年度のリリースからRaspberry PiにOracle Javaが標準パッケージとしてインストールされるようになりました!Raspberry Pi Foundation FounderであるEben UptonもPythonの他JavaもRaspberry Piで使えるプログラミング言語として注目をしております。ここではごく簡単にRaspberry Piのご紹介とJava Embedded on Raspberry Piのアップデートについてお話しいたします。

コマンドプロンプトの代わりにckw + NYAOSを使ってみた。

コマンドプロンプトの代わりになるコンソールckwとUnixライクのコマンドを使えるNYAOSをつかってみました。
コマンドプロンプトでls、pwdがないとか、コピペが云々とか、横幅が、見栄えが、とか思う所があるならば使ってみるとよいかも。

モジュール取得

それぞれの公式サイトから最新版のモジュールを取得。

私の場合は以下のバージョンでした。

  • ckw-mod-0.9.1.zip
  • nyaos-3.3.8_3-win.zip

インストールと設定

  • それぞれを解凍して、nyaosの中身を全て、ckwのディレクトリの中に移動。
ckw
├ChangeLog.txt
├ckw.cfg
├ckw.exe
├licence.txt
├nyaos.exe
├nyaos_en.txt
├nyaos_ja.txt
├ReadMe.txt
├_nya
└_nya.d
  ├cmdsource.lua
  ├compatible.ny
  ├exever.lua
  ├fc.lua
  ├forvimshell.lua
  ├gpath.lua
  ├gui_cd.lua
  ├ln.lua
  ├lnk.lua
  ├lslua.lua
  ├mount.lua
  ├quote_eval.lua
  ├quote_luaexp.lua
  ├readme.txt
  ├which.lua
  └opt
     ├auto_cd.lua
     ├browse.lua
     └vz.ny
  • ckw.cfgを編集
Ckw*title: ckw[cmd]
Ckw*exec:  cmd.exe

の箇所を↓に編集。

Ckw*title: ckw[nyaos]
Ckw*exec:  nyaos.exe
  • 配色を変えたい場合には適当に色を変更。私は↓を参考にしました。

Windowsのコマンドプロンプトをフリーソフトで便利にする - ナレッジエース

  • _nyaを編集

_nyaの最下部に下記を追記(パスは適当に変更してください。)

option savehist "C:\tools\ckw\.history"

サクラエディタで新規ファイルをUTF-8で開く方法。

サクラエディタで新規ファイルを開く際にデフォルトだと「SJIS」で開こうとするので、保存時に変えるのがめんどくさい。
なので、デフォルトで変更したい。

どこかで設定できるだろうけど、設定項目多いのでグーグル先生で検索。

バージョン2.0.4.0 以降であれば

設定(O) > タイプ別設定(Y) > 「支援」タブ > 「デフォルトの文字コード
UTF-8 へ変更が可能です。

サクラエディタを開いた時の文字コードをUTF-8にする方法 - 零弐壱蜂

バージョンは2.1.0.0なのにない。
念のため最新版の2.1.1.1にしてみたけどない。

何か不具合でもあって消された?
なので、マクロ組みました。
新規時と、空のファイルはUTF-8で開きます。

if (ExpandParameter('$F') == '(無題)' || GetLineCount(0) == 0) {
FileReopenUTF8(0); 
}

独自関数とか知らないので↓を参考にしました。

マクロの設定は↓参照。