xtend30分クッキング やきに駆動
DESCRIPTION
やきに駆動の資料TRANSCRIPT
30分クッキング
Xtend
30分クッキング
Xtend
IT'S JUST Java
Xtend Extends Java
愛 焼 肉は にある。
30分 クッキングXtend
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
Javaソースへ変換
ローカル型推論
プロパティ
Xtend at JavaOne
Xtend news!JavaOne 2012
10/2 10:00Sebastian's プレゼンテーション on Xtend
Video is onlinehttps://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=6630
30分クッキング
Xtend
愛 X tendは にある。
やきに駆動の提供でお送りします。
@s_kozake 先生 s_kozake せんせい
Xtend研究家・トラブル火消士。某大学卒業後、某大手 SIer企業での下積み (常駐 )を経て自社のビックプロジェクトに従事するに至る。2人の娘さんの父親でもあり、過酷な育児の日々の中、「 No ドラクエ Noライフ」で廃人まっしぐら中。
著プレゼン / LT (http://www.slideshare.net/s_kozake)
「 Play! Together」( Play Framework 勉強会 in 関西) 「 About Jobs 」(やきに駆動秋の Java 祭典スペシャル in 大阪~こりん星) 「MyBatis で流れるようなメソッドチェーン」(やきに駆動秋の Java 祭典スペシャル in 大阪~こりん星) 「システムアーキテクトになる前に覚えておきたい技術とか色々」(鹿駆動勉強会) 「たのしい関数型」(第 1 回関数型言語勉強会大阪) 「 Xtend30分クッキング」(関 Java '12 8 月度)
著ブログ (http://ameblo.jp/kozake)
「はじめての変態」(変態アドベントカレンダー 2011) 「変態アドベントカレンダー 2011の QR コード作りました」(変態アドベントカレンダー 2011) 「 cron4jのご紹介」( Java Advent Calendar 2011 ) 「 Play Excel!」( Play! framework Advent Calendar 2011 ) 「おめでたい話と悩みごと」(変態アドベントカレンダー 2011)
先生のレシピ先生のレシピ
本日のレシピ『 Xtend』
Javaランタイムに完全な互換性をもつ、ラムダを備えた Java互換言語
Xtextという DSLライブラリおよびエディタ生成のためのプラグインスイートをベース
What's Xtend?
Pythonや Rubyと同等の表現力
互換性問題のない Java
Javaの構文とコンセプトをできるだけ再利用
Javaアプリケーションを読みやすく表現力高く
Xtendのコンセプト
Xtendは Javaのソースファイルを生成する
0: aload_01: invokespecial4: return0: getstatic3: ldc #3; 5: invokevirtual8: return
import org.eclipse.xtext.xbase.lib.InputOutput;
public class HelloWorld { public static void main(final String[] args) { InputOutput.<String>println("Hello World"); }}
0: aload_01: invokespecial4: return0: getstatic3: ldc #3; 5: invokevirtual8: return
Javaバイトコード
Javaソースコード Javaバイトコード
要するに、 Javaにとっての「 CoffeeScript」
Xtendのコンパイル方法
・ Eclipseビルダ経由
・Mavenプラグイン
コンパイラは Eclipseとは完全に独立
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
IT'S JUST Java
Java技術者の習得コストが少ない=技術者確保が容易
Why Xtend?
Javaの既存資産が活用できる
静的型付けであり、 Javaと同等の性能
Why Xtend?
DSL拡張メソッド、演算子上書き、テンプレート式など、内部 DSLを作成する便利機能がそろっている
下ごしらえ( Installation)
Xtend <1人分 >
Eclipse Juno ---------------------------1 Download
コーヒー ------------------------------5~ 10 本
Windows7 -----------------------------1 ライセンス
嫁の理解 ------------------------------2人日
Xtend-2.3.1 ----------------------------1 Download
やる気 ---------------------------------少々
Help → Install New Software
http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/
下の URLを入力し、 Xtend-2.3.1を選択。
Next
Check「 I accept.. → 」 Finish
Download.... → restart
New → Java Project
Input Project name → Next
Add Library
Select 「 Xtend Library → 」 Next
Finish
試食( Demo)
Demoソース「 Hello World」
package demo
class HelloWorld { def static void main(String... args) { println('Hello World!') }}
HelloWorld.xtend
package demo;
import org.eclipse.xtext.xbase.lib.InputOutput;
@SuppressWarnings("all")public class HelloWorld { public static void main(final String... args) { InputOutput.<String>println("Hello World!"); }}
HelloWorld.java
Demoソース「 FizzBuzz」
package demo
class FizzBuzz {
def static void main(String... args) { new FizzBuzz().run }
def void run() { var i = 1 while (i <= 100) { println(fizzbuzz(i)) i = i + 1 } }
def String fizzbuzz(int i) { if (i % 15 == 0) { return 'fizzbuzz' } else if (i % 3 == 0) { return 'fizz' } else if (i % 5 == 0) { return 'buzz' } else { return String::valueOf(i) } }}
FizzBuzz.xtend
package demo
class FizzBuzz2 {
def static void main(String... args) { new FizzBuzz2().run; }
def void run() { (1..100).forEach [ println(it.fizzbuzz) ] }
def fizzbuzz(int i) { switch i { case (i % 15 == 0) : 'fizzbuzz' case (i % 3 == 0) : 'fizz' case (i % 5 == 0) : 'buzz' default : i.toString } }}
FizzBuzz2.xtend
MoreSimple
Demoテストソース「 FizzBuzz2Test」
package demo
import static org.junit.Assert.*;import static org.hamcrest.CoreMatchers.*;
import org.junit.Test
class FizzBuzz2Test {
extension FizzBuzz2 test = new FizzBuzz2()
@Test def testFizzBuzz() {
assertThat (1.fizzbuzz, is('1')) assertThat (3.fizzbuzz, is('fizz')) assertThat (5.fizzbuzz, is('buzz')) assertThat (15.fizzbuzz, is('fizzbuzz')) }}
FizzBuzz2Test.xtend
調理(機能紹介)
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
既存の型に変更なしに新しいメソッドを追加できます。
拡張メソッド
Xtendの名前はこの機能からきています。
機能自体は単純な仕組み拡張メソッドの最初のパラメータを渡す代わりにそのメンバの 1つであるかのようにメソッドが呼ばれます。
15.fizzbuzz // call fizzbuzz(15)
拡張メソッド(利点)
ネストされたメソッド呼び出し(コマンドクエリー IF)でなくチェインされたメソッド呼び出し(流れるような IF)が可能可読性が増します。
特定のコンテキストやアプリケーション層に固有メソッドを追加できます。
JsonUtil::writeJson(obj)
obj.writeJson
でなく
拡張メソッド(組み込みライブラリ)
デフォルトで既存クラスの拡張メソッドが用意されています。
・ ObjectExtensions ・ IterableExtensions ・ MapExtensions ・ ListExtensions ・ CollectionExtensions ・ BooleanExtensions ・ IntegerExtensions ・ FunctionExtensions
val obj = newArrayList(1,2,3)println(obj.map[it * 2]) // [2, 4, 6]println(obj.getClass.getName) // java.util.ArrayList
拡張メソッド(ローカル Extensionインポート)
クラス内または親クラスの可視性のある非 staticメソッドは自動的に拡張メソッドとして使えます。
def void run() { println(15.fizzbuzz)}
def fizzbuzz(int i) { switch i { case (i % 15 == 0) : 'fizzbuzz' case (i % 3 == 0) : 'fizz' case (i % 5 == 0) : 'buzz' default : i.toString }}
拡張メソッド( Extensionインポート)
ヘルパークラスなどが用意する staticメソッドは、import staticの後ろに extensionキーワードを配置することで、全ての staticメソッドを拡張メソッドとしてimportできます。
package demo
class JsonUtil { def static writeJson(Object obj) { println(obj.toString) } }
package demo
import static org.junit.Assert.*;import static org.hamcrest.CoreMatchers.*;import static extension demo.JsonUtil.*;
import org.junit.Test
class TestJsonUtil {
@Test def void testWriteJson() {
val obj = 'test' obj.writeJson }}
staticImportextension
拡張メソッド( Extensionフィールド)
フィールド定義に extensionキーワードを追加すると、そのインスタンスのメソッドは拡張メソッドとなります。
class FizzBuzz2Test {
extension FizzBuzz2 test = new FizzBuzz2()
@Test def testFizzBuzz() {
assertThat (1.fizzbuzz, is('1')) : }}
staticな extension importと比べて、フィールド定義によるextensionの利点は、実装にバインドされないことです。factoryや依存性注入、 setterメソッドにより外部から実装を簡単に交換できます。
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
ローカル型推論
変数の型は右の式から推論されます。また、メソッドの戻り値もメソッド本体から推測されます。
package demo
import java.util.Date
class DemoClass { val a = 1 var b = 'test' public var c = 2
def hoge() { val d = new Date 'hoge' }}
package demo;
import java.util.Date;
@SuppressWarnings("all")public class DemoClass { private final int a = 1; private String b = "test"; public int c = 2; public String hoge() { String _xblockexpression = null; { Date _date = new Date(); final Date d = _date; _xblockexpression = ("hoge"); } return _xblockexpression; }}
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
Xtendはステートメントを持っていません。全てが式で戻り値を持っています。全ての式を紹介する時間がないので、いくつかの式を紹介します。
ステートメントレス(全てが式)
ifは pの結果により e1か e2を返す式です。
ステートメントレス( if式)
val a = if (true) 1 else 2println(a) // 1
if (p) e1 else e2
val a = if (false) 1val b = if (false) 'a'println(a) // 0println(b) // null
elseをオプションで省略可能です。
forは voidを返す式です。variableの型は arrayOrIterableの型から型推論されるので省略可能です。
ステートメントレス( for式)
val arr = newArrayList(1,2,3,4,5)for (i : arr) { println(i)}
for (T1 variable : arrayOrIterable) expression
try-catchも式です。以下のようなコードを書くことで今まで必要だったローカル変数を省略できます。
ステートメントレス( try-catch式)
val s = 'a'val n = try { Integer::parseInt(s)} catch (NumberFormatException ex) { -1}println(n) // -1
ローカル変数 itを使用すると、 itに代入されたインスタンスのフィールドやメソッドがローカルのように扱えます。
ステートメントレス(その他)
package demo
class Hoge { @Property String fuga}
class DemoClass {
def static void main(String... args) { val it = new Hoge fuga = 'test' println(fuga) // test }}
?.によるメソッド呼び出しで、 null安全な呼び出しが可能です。
ステートメントレス(その他)
var hoge = new Hogehoge?.hello
hoge = nullhoge?.hello
Hoge _hoge = new Hoge();Hoge hoge = _hoge;if (hoge!=null) hoge.hello();hoge = null;if (hoge!=null) hoge.hello();
Staticアクセスは .でなく ::でアクセスします。
ステートメントレス(その他)
val n = Integer::parseInt('1')println(n)
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
Switch式は Javaの switch文とはかなり異なっています。
強力な Switch式
・下への落下がない ・特定の値に限定されず、任意のオブジェクトが使用可能
val s = 'ho'val ret = switch s + 'ge' { case s.length > 5 : 'so long' case 'hoge' : 'equal hoge' default : 'not'}println(ret) // equal hoge
まず、 switchの式が評価されます。式の型が boolean型なら、 trueで caseにマッチします。boolean型以外なら、 Object.equals(Object)が比較に使用されます。caseにマッチしたら、コロンの後の式が評価され、式全体の結果となります。
ケースガードに加え、型ガードもサポートしています。
強力な Switch式
def length(Object x) { switch x { String case x.length > 0 : x.length // length is define String List<?> : x.size // size is define for List default : -1 }}
switchの値が型と一致しているのみ、ケースと比較します。型と一致しない場合、 caseの式は評価されません。両方が一致した場合、コロンの後の式が評価されます。switchの値が変数の場合、自動的にその型にキャストされます。
Javaの instance of やキャストに比べて読みやすく型安全です。
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
Xtendは SAM(Single Abstract Method) Typeのインタフェースをラムダ式として表せます。
ラムダ
public interface Hello {void hello(String s);
}
class DemoClass {
def static void main(String... args) { helloWorld([String s | println(s)]) } def static void helloWorld(Hello o) { o.hello('hello world!') }}
上記のように角括弧で囲んだ部分がラムダ式です。この構文は、 Smalltalkに影響を受けたらしいです。| の区切りでパラメータ宣言と式が書かれています。
ラムダ
public interface Hello {void hello(String s);
}
class DemoClass {
def static void main(String... args) { helloWorld([String s | println(s)]) } def static void helloWorld(Hello o) { o.hello('hello world!') }}
パラメータの型はインタフェースの型から推測できるので、省略可能です。
ラムダ
public interface Hello {void hello(String s);
}
class DemoClass {
def static void main(String... args) { helloWorld([println(it)]) } def static void helloWorld(Hello o) { o.hello('hello world!') }}
パラメータが 1つの場合、パラメータ宣言が省略可能です。省略した場合、パラメータは itという名前の変数にバインドされます。
ラムダ
public interface Hello {void hello();
}
class DemoClass {
def static void main(String... args) { helloWorld([| println('hello world!')]) } def static void helloWorld(Hello o) { o.hello() }}
パラメータないメソッドは上記のように書けます。| の記述がいることに注意してください。
ラムダ
public interface Hello {void hello(String s);
}
class DemoClass {
def static void main(String... args) { helloWorld(3) [ println(it) ] } def static void helloWorld(int n, Hello o) { (1..n).forEach [ o.hello('hello world!') ] }}
メソッド一番右側のパラメータがラムダ式の場合、パラメータリストの後に渡すことができます。
ラムダ
public interface Hello {void hello(String s);
}
class DemoClass {
def static void main(String... args) { val name = 'duke' helloWorld [ println(it + ' ' + name) ] } def static void helloWorld(Hello o) { o.hello('hello world!') }}
Java同様、ラムダ式の外部の final変数参照することが可能です。
ラムダ
val f = [int n | n**3 ]println(f.apply(2)) // 8.0
SAM Typeがなくても、下記のように書けます。
final Function1<Integer,Double> _function = new Function1<Integer,Double>() { public Double apply(final Integer n) { double _power = Math.pow(n, 3); return _power; }};final Function1<Integer,Double> f = _function;Double _apply = f.apply(Integer.valueOf(2));InputOutput.<Double>println(_apply);
戻り値が voidの場合、 Procedures、それ以外は Functionsとなります。
ラムダ
val (int) => double f = [int n | n**3 ]println(f.apply(2)) // 8.0
Xtendは関数型の簡略構文もサポートしています。
val Function1<Integer,Double> f = [int n | n**3 ]println(f.apply(2)) // 8.0
=
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
中置演算子と演算子のオーバーロード
Javaとは対照的に、演算子は特定の型の操作に限定されません。任意の型の演算子を再定義し、対応するメソッドシグネチャを実装することで、演算子からメソッドへのマッピングが可能です。例えば、ランタイムライブラリには、 BigDecimalの演算子
を定義するクラス BIgDecimalExtensions が含まれています。
val a = 1BDval b = 2BD
println(a.getClass.getName) // java.math.BigDecimalprintln(b.getClass.getName) // java.math.BigDecimal
println (a + b) // 3
中置演算子と演算子のオーバーロード演算子のオーバーロードが可能です。
package demo
@Dataclass DemoClass {
String hoge
def DemoClass operator_add(DemoClass obj) { new DemoClass(this.hoge + obj.hoge) }
override toString() { hoge }
def static void main(String... args) { val a = new DemoClass('hoge') val b = new DemoClass('fuga')
println(a += b) // hogefuga }}
中置演算子と演算子のオーバーロード
使用可能な演算子とそれに対応するメソッドシグネチャの完全なリストです。また、下の表は昇順で演算子の優先順位を定義しています。
e1 += e2 e1.operator_add(e2)e1 || e2 e1.operator_or(e2)e1 && e2 e1.operator_and(e2)e1 == e2 e1.operator_equals(e2)e1 != e2 e1.operator_notEquals(e2)e1 < e2 e1.operator_lessThan(e2)e1 > e2 e1.operator_greaterThan(e2)e1 <= e2 e1.operator_lessEqualsThan(e2)e1 >= e2 e1.operator_greaterEqualsThan(e2)e1 -> e2 e1.operator_mappedTo(e2)e1 .. e2 e1.operator_upTo(e2)e1 => e2 e1.operator_doubleArrow(e2)e1 << e2 e1.operator_doubleLessThan(e2)e1 >> e2 e1.operator_doubleGreaterThan(e2)e1 <<< e2 e1.operator_tripleLessThan(e2)e1 >>> e2 e1.operator_tripleGreaterThan(e2)
e1 <> e2 e1.operator_diamond(e2)e1 ?: e2 e1.operator_elvis(e2)e1 <=> e2 e1.operator_spaceship(e2)e1 + e2 e1.operator_plus(e2)e1 – e2 e1.operator_minus(e2)e1 * e2 e1.operator_multiply(e2)e1 / e2 e1.operator_divide(e2)e1 % e2 e1.operator_modulo(e2)e1 ** e2 e1.operator_power(e2)! e1 e1.operator_not()- e1 e1.operator_minus()
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
テンプレート式は読みやすい文字連結を提供します。
・ 3つのシングルクォートで囲まれています。・複数行にまたがることができます。・評価される式をネストできます。
テンプレート式
class TemplateSample {def static void main(String... args) {
println(hello("world"))}
def static hello(String s) '''hello «s»
'''}
いろんなところで使うことができます。
テンプレート式
import static extension demo.TemplateSample.*
class TemplateSample {def static void main(String... args) {
(1..100).forEach [ println(it.fizzbuzz) ]}
def static fizzbuzz(int i) {switch i {
case (i % 15 == 0) : '''fizzbuzz(«i»)'''case (i % 3 == 0) : '''fizz(«i»)'''case (i % 5 == 0) : '''buzz(«i»)'''default : '''«i»'''
}}
}
テンプレート式で使用できる特別な IF文があります。
テンプレート式
import static extension demo.TemplateSample.*
class TemplateSample {def static void main(String... args) {
(1..100).forEach [ println(it.fizzbuzz) ]}
def static fizzbuzz(int i)'''«IF i % 15 == 0»fizzbuzz«ELSEIF i % 3 == 0»fizz«ELSEIF i % 5 == 0»buzz«ELSE»«i»«ENDIF»'''
}
FOR文もありますよ。
テンプレート式
import static extension demo.TemplateSample.*
class TemplateSample {def static void main(String... args) {
println(100.fizzbuzz)}
def static fizzbuzz(int n)'''«FOR i : (1..n)»«IF i % 15 == 0»fizzbuzz«ELSEIF i % 3 == 0»fizz«ELSEIF i % 5 == 0»buzz«ELSE»«i»«ENDIF»«ENDFOR»
'''}
Xtendの機能
拡張メソッド
ラムダ
演算子上書き
強力な Switch式
ステートメントレス(全てが式)
テンプレート式
ローカル型推論
プロパティ
プロパティフィールド変数を@Propertyアノーテーション定義することでsetter / getterを自動生成してくれます。
class DemoClass {
@Property String hoge}
@SuppressWarnings("all")public class DemoClass { private String _hoge; public String getHoge() { return this._hoge; } public void setHoge(final String hoge) { this._hoge = hoge; }}
フィールドが指定されたコンテキストからアクセスできない場合、 setterが使用されます。これが@Propertyアノーテーションがローカルフィールドを_myProperty にリネームする理由です。
プロパティ
また、クラス定義に@Dataアノーテーション定義することで値オブジェクトとしてクラスを定義できます。
@Dataclass DemoClass {
String hoge}
import org.eclipse.xtend.lib.Data;import org.eclipse.xtext.xbase.lib.util.ToStringHelper;
@Data@SuppressWarnings("all")public class DemoClass { private final String _hoge; public String getHoge() { return this._hoge; } public DemoClass(final String hoge) { super(); this._hoge = hoge; } @Override public int hashCode() { : @Override public boolean equals(final Object obj) { : @Override public String toString() { :}
まとめ
モダンな言語機能を備えている。
・ラムダ・型推論・強力な Switch式・ etc..
既存機能を拡張できる
・拡張メソッド
Xtend Extends Java
既存のリソースを活用できる
・豊富な OSS・ IDEサポート・様々な経験知・ etc..
Javaである
IT'S JUST Java
なによりも・・・
愛 Hoge 駆動は にある。
やきに駆動の提供でお送りしました。
30 分 Xtend クッキング
Thank you a lot