2016年5月31日

C# 文字列リテラル(補間文字列・逐語的文字列)まとめ

C# 6.0 から補間文字列が追加されて、文字列リテラルの種類が 4 つに増えている。
MSDN にまとめた記事が無いので(たぶん)、自分用まとめ

書式 バックスラッシュ
エスケープ
改行 補間式 その他の
エスケープ
標準 "regular"
逐語的 @"verbatim
string"

"" → "

補間 $"1+1={1+1}"

{{ → {

}} → }

補間
逐語的
$@"interpolated
{"and"}
verbatim"

"" → "

{{ → {

}} → }


また、補間文字列の補間式の中に各種文字列リテラルを書くことが可能。
つまり、補間文字列のネストも可能。(実用性は無さそうだけど)
ただし、改行を許可しない補間文字列の中に、逐語的文字列や補間逐語的文字列を書いても改行を含めることはできない。(コンパイルエラー)

// 逐語的(改行無し) in 補間 : OK
var nested1 = $"this is {@"verbatim string"}";

// 逐語的(改行有り) in 補間逐語的 : OK
var nested2 = $@"this is {@"verbatim
string"}";


// 逐語的(改行有り) in 補間 : ERROR
var nested_error = $"this is {@"verbatim
string"}";

参考URL

2016年5月25日

Kotlin から見た Java の getter / setter (getXXX / isXXX / setXXX)

Calling Java code from Kotlin - Getters and Setters の補足みたいな話。
Kotlin 1.0.2

Kotlin から Java のコードを呼ぶ際、getter / setter (getXXX / isXXX / setXXX メソッド) はプロパティとして扱える。
詳細なルールとしては、
getter
  • get{X} または is{X} で始まる引数無し・戻り値ありのインスタンスメソッド
    {X} は小文字と解釈されない文字、日本語でもOK
  • getXXX / isXXX でプロパティ名の規則が異なる
    • getHoge メソッド → hoge プロパティ
    • isHoge メソッド → isHoge プロパティ
  • isXXX の戻り値の型は問わない (Boolean 以外でも可)
setter
  • set{X} で始まる引数 1 つのインスタンスメソッド
  • 戻り値の有無は問わない (あってもいい)
  • 対になる getter が必要 (Kotlin は今の所 set-only プロパティをサポートしてないため)

[ルールのサンプル (Java)]

// Kotlin でプロパティになるケース (メソッドとして使用できない)
public class PropertySample {
    public String getName() { /* 略 */ }
    public void setName(String name) { /* 略 */ }
    // [Kotlin] public final var name: String!
    // getter/setter があるので var プロパティ

    public Boolean isKey() { /* 略 */ }
    public void setKey(Boolean key) { /* 略 */ }
    // [Kotlin] public final var isKey: Boolean!
    // getter が isXXX の場合、プロパティ名は同じ(isXXX)

    public Boolean getKey() { /* 略 */ }
    // [Kotlin] public final var key: Boolean!
    // getter が isXXX と getXXX の 2 つ存在する場合、プロパティも 2 つになる
    // setter は共通 (両方のプロパティから使用される)

    public int getId() { /* 略 */ }
    // [Kotlin] public final val id: Int
    // getter のみは val プロパティ

    public String getあ() { /* 略 */ }
    public String setあ(String あ) { /* 略 */ }
    // [Kotlin] public final var あ: String!
    // 日本語可、setter に戻り値があっても可
}

// Kotlin でプロパティにならないケース (メソッドとして使用できる)
public class NotPropertySample {
    // setter のみ
    public void setNum(int num) { /* 略 */ }

    // 小文字スタート
    public int geta() { /* 略 */ }

    // static メソッド
    public static int getStatic() { /* 略 */ }

    // プロパティ名がかぶる
    public String getUrl() { /* 略 */ }
    public String getURL() { /* 略 */ } // 全部大文字の場合、プロパティ名は小文字になる
}

雑記

isXXX は混乱の元になりそうなのであまり使いたくないところ。
でも Kotlin から Java を呼び出すケースって、おそらく既存ソースの再利用で isXXX がある可能性もそれなりにあって・・・

ちなみに Java から Kotlin のプロパティを使用する際は、逆のイメージ。
  • XXX プロパティ → getXXX / setXXX メソッド
  • isXXX プロパティ → isXXX / setXXX メソッド

2016年3月23日

Kotlin null 許容型 (nullable) の外し方(スマートキャスト)

Kotlin の null 許容型 (nullable type) の変数は、if 等の制御文を挟むことで、null 非許容型 (non-null type) に自動でキャストされる。
null 許容型はコンパイル時にしか存在しないので、バイトコードにキャスト処理が入るわけではない。
IntelliJ IDEA だと、自動キャストされた変数はハイライトされて、マウスオーバーすると「Smart cast to 型名」がポップアップされるので分り易い。

ここでは、どんな制御文で null 許容型からのスマートキャストが可能か(コンパイラがどこまでやれるのか)、色々試してみる。
Kotlin 1.0.1 なので、バージョンが上がると挙動が変わるかも。

1 変数の場合

  1. if で null 除外
    
    fun ifNotNull(x: Any?) {
        if( x != null ) println(x.javaClass)
    }
    
    基本。
  2. if で null の場合、return
    
    fun ifNullReturn(x: Any?) {
        if( x == null ) return
        println(x.javaClass)
    }
    
    (1) の逆バージョン。
  3. when で null 除外
    
    fun whenNotNull(x: Any?) {
        when( x ){
            null -> {}
            else -> println(x.javaClass)
        }
    }
    
    (1) の when バージョン。if 使った方がいい。
  4. when で null の場合、return
    
    fun whenNullReturn(x: Any?) {
        when( x ){
            null -> return
            else -> {}
        }
        println(x.javaClass)
    }
    
    (2) の when バージョン。これも if 使った方がいい。
    また、else を省略するとコンパイルエラー( .javaClass で)。
  5. エルビス演算子 ?: で null の場合、return
    
    fun elvisNullReturn(x: Any?) {
        x ?: return
        println(x.javaClass)
    }
    
    (2) のエルビス演算子バージョン。
    少し魔術っぽいけど、慣れたら問題ない・・・? タイプ量が少なくなるから使いそう。
    return の代わりに例外 throw も可。
  6. ぬるぽ演算子 !! で null の場合、例外
    
    fun nullpo(x: Any?) {
        x!!
        println(x.javaClass)
    }
    
    ほとんどの場合、バッドプラクティス。(ぬるぽ演算子の使い所は難しい・・・)
    !! 演算子は特に名前が無いようなので、"ぬるぽ演算子"の呼び方は非公式
  7. while で null 除外
    
    fun whileNotNull(x: Any?) {
        while( x != null ){
            println(x.javaClass)
            break
        }
    }
    
    (1) の while バージョン。使い所はあまり無い気がするけど、一応可能。
  8. while で null の場合、return
    
    fun whileNullReturn(x: Any?) {
        while( x == null ) return
        println(x.javaClass)
    }
    
    (2) の while バージョン。使い所なんて無い気がするけど、一応可能。
  9. [NG] if-true ネストで if-return
    
    fun ifNullReturnIfNest(x: Any?) {
        if( true ){
            if( x == null ) return
        }
        println(x.javaClass) // コンパイルエラー
    }
    
    ありえないコードは、ネストの中まで見てくれない模様。
  10. while-true ネストで if-return
    
    fun ifNullReturnWhileNest(x: Any?) {
        while( true ){
            if( x == null ) return
            break
        }
        println(x.javaClass)
    }
    
    if と異なり while ならネストの中まで見てくれる・・・。
    while の条件を変数にすると、コンパイルエラー。
    たぶん、while-true がありえるかもしれないコードだからだと推測。
  11. [NG] when-true ネストで if-return
    
    fun ifNullReturnWhenNest(x: Any?) {
        when {
            true -> if( x == null ) return
        }
        println(x.javaClass) // コンパイルエラー
    }
    
    これもありえないコードなので不可。when に else があっても不可。
  12. [NG] with 関数のラムダ式で if-return
    
    fun ifNullReturnWithScope(x: Any?) {
        with( x ){
            if( x == null ) return // この return は ifNullReturnWithScope を抜ける
    
            // 本来、with 内で x にアクセスする際は this を使う
        }
        println(x.javaClass) // コンパイルエラー
    }
    
    VB でお馴染みの With だが、Kotlin では関数 + ラムダ式になっている。(組み込みの構文ではない。)
    with 関数はインライン展開されるけど、さすがに関数の中まで見てくれない。

2 変数の場合

  1. if で null 除外
    
    fun ifNotNull(x: Any?, y: Any?) {
        if( x != null && y != null ){
            println(x.javaClass)
            println(y.javaClass)
        }
    }
    
    単純な複合条件は可能。
    引数無し when でも同様に可能。
  2. if で null の場合、return
    
    fun ifNullReturn(x: Any?, y: Any?) {
        if( x == null || y == null ) return
        println(x.javaClass)
        println(y.javaClass)
    }
    
    (1) の逆バージョン。
    引数無し when (else 有り) でも同様に可能。
  3. if-else-if で順番に null 除外
    
    fun ifNotNullEach(x: Any?, y: Any?) {
        if( x == null ){
            // x は null、y は null かも
        } else if( y == null ){
            // x は 非 null、y は null
            println(x.javaClass)
        } else {
            // x、y ともに非 null
            println(x.javaClass)
            println(y.javaClass)
        }
    }
    
    一度 null を除外すれば、次のブロックでも有効。
    引数無し when でも同様に可能。
  4. [NG] if-else-if で順番に複合条件で null 除外
    
    fun ifNotNullComplex(x: Any?, y: Any?) {
        if( x == null && y == null ){
            // x、y ともに null
        } else if( x != null && y == null ){
            // x は 非 null、y は null
            println(x.javaClass)
        } else if( x == null && y != null ){
            // x は null、y は 非 null
            println(y.javaClass)
        } else {
            // x、y ともに非 null のはず
            println(x.javaClass) // コンパイルエラー
        }
    }
    
    コンパイラが複雑になるから見てないのだと推測。特に変数が増えた場合やばそう・・・
    人間が見ても else ブロックで null 除外されていることは、分かりづらいと思う。

2016年3月10日

Kotlin null 許容型 (nullable) はコンパイル時だけの存在

Kotlin の目玉機能の 1 つ「null 安全」のために null 許容型 (nullable type) が存在するが、これはコンパイル時だけの存在で、実体クラスが定義されているわけではない。
C# / VB.NET 経験者なら Nullable<T> 相当のクラスがあるのか?と思うかもしれないが、そんなものは無い。

たぶん、Java コードとの共存 + 実行時のパフォーマンスが考慮された仕様になっている。

一応、下記で検証可能。

fun main(args: Array<String>) {
    printType<Int>()
    printType<Int?>()
    // Int?::class だとコンパイルエラー (直接 println できない)
}

inline fun <reified T> printType() {
    println(T::class)
}

//[結果]
// class kotlin.Int
// class kotlin.Int
※ 2 行目と 3 行目で生成されるバイトコードは同じ

検証環境

  • jdk 1.8.0_74
  • Kotlin 1.0.0

2016年2月12日

Kotlin 遅延評価型と先行評価型のコレクション操作関数

"ことりん" の名前が気に入ったので色々調査中・・・
(・8・) × >ω</

Kotlin のコレクション操作関数(C# の LINQ to Object、Java の Stream API 相当)は、1.0.0-rc-1036 時点で stdlib に 2 種類用意されている。
Sequence インターフェース の拡張関数(遅延評価型)と、Iterable インターフェース の拡張関数(先行評価型)である。
※ スカラ値を返す関数(any, count, max 等)は両方とも先行評価型

よって、正確には、LINQ to Object や Stream API 相当になるのは、Sequence 拡張関数の方になる。

[Sequence と Iterable 拡張関数の比較]

fun main(args: Array<String>) {
    val source = 0..3
    lazyEvaluationMethods(source)
    println()
    eagerEvaluationMethods(source)
}

// 数字リストから偶数のみを抽出して 2 倍する

fun lazyEvaluationMethods(source : Iterable<Int>) {
    var result = source.asSequence().filter {
        println("sequence.filter : $it")
        it % 2 == 0
    }.map {
        println("sequence.map : $it")
        it * 2
    }.toList()
    println(result)
}

fun eagerEvaluationMethods(source : Iterable<Int>) {
    var result = source.filter {
        println("iterable.filter : $it")
        it % 2 == 0
    }.map {
        println("iterable.map : $it")
        it * 2
    }
    println(result)
}
[結果]
sequence.filter : 0
sequence.map : 0
sequence.filter : 1
sequence.filter : 2
sequence.map : 2
sequence.filter : 3
[0, 4]

iterable.filter : 0
iterable.filter : 1
iterable.filter : 2
iterable.filter : 3
iterable.map : 0
iterable.map : 2
[0, 4]

検証環境

  • jdk 1.8.0_74
  • Kotlin 1.0.0-rc-1036

雑記

Sequence と Iterable の違いを知ってないと割と危険な実装をしてしまいそう・・・
Iterable 拡張関数の方は戻り値が kotlin.collections.List 型なのですぐに気付くはず。
その List の実装は、今のところ java.util.ArrayList が利用されている。

2016年2月10日

Kotlin ジェネリクス 型引数の情報を実行時に取得

Kotlin 正式版がそろそろリリースされそうなので・・・
GitHub - temp-impl/spring-mvc-singleton-vs-prototype_kotlin を作った時の調査メモ。)

Kotlin も JVM 言語なので、コンパイル時型消去の呪いからは逃れられない。
が、inline と reified を使うことで、関数・メソッドなら型引数の情報を実行時に使用可能になる。

[型引数使用サンプル]

fun main(args: Array<String>) {
    printType<String>()
}

inline fun <reified T> printType() {
    println(T::class)
}

//[結果]
// class kotlin.String

//[補足]
// 上記結果を得るためには kotlin-refrect.jar も必要
// 無くてもエラー無しで実行できるが、下記結果になる
// class java.lang.String (Kotlin reflection is not available)
[上記のバイトコード(一部)]

   L2
    LINENUMBER 8 L2
    LDC Ljava/lang/String;.class
    INVOKESTATIC kotlin/jvm/internal/Reflection.getOrCreateKotlinClass (Ljava/lang/Class;)Lkotlin/reflect/KClass;
    ASTORE 1
    NOP
   L3
    LINENUMBER 11 L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V

inline というキーワードから想像が付くと思うが、関数の中身がインライン展開されている。
そのため、型引数の情報も当然使用可能。

ちなみに Java クラスの情報が欲しい場合

inline fun <reified T : Any> printJavaType() {
    println(T::class.java)
}

//[結果] (上と同じ main)
// class java.lang.String

//[補足]
// 型引数のデフォルト上限は Any? で Java に無いクラスなので、Any 上限を指定する必要がある
// .java は KClass<T : Any> の拡張プロパティ

検証環境

  • jdk 1.8.0_74
  • Kotlin 1.0.0-rc-1036

雑記

inline 関数の型引数はデフォルト reified でも良さそうと思ったが、たぶん Kotlin は(型引数使用を)明示していくスタイルなのだろう。
(コンパイラの都合もあるかもしれない・・・)

Scala の implicit + ClassTag みたいな仕組みはおそらく導入されない。
Comparison to Scala - Kotlin Programming Language を読むと implicit は導入する気が無さそうなので。

2016年1月30日

Spring @Autowired フィールドを持つクラスを手動で生成

初めて Spring を触って、@Autowired の便利さに感動したので・・・

前置き

@Autowired について簡単に説明すると、自動で初期化されるフィールドの目印。
(フィールドだけでなくセッターメソッドに対しても使用可能)
つまり、コンストラクタやフィールドの右辺に、フィールドの初期化処理を書かなくてよくなる。
古い Spring では初期化設定を xml に書く必要があったが、今はアノテーション(C# での カスタム属性)のみで完結できるようになっている。

[@Autowired サンプル]

@Controller
public class HogeController {

    @Autowired
    private HogeService service;

    // 以降、URL 割り当てメソッド
}

@Service
public class HogeService {

    @Autowired
    private HogeDao dao;

    // 以降、サービスメソッド
}

@Component
public HogeDao {}
HogeController にマップされた URL アクセス時、HogeController インスタンスがフレームワークによって生成され、@Autowired フィールドの service にも HogeService インスタンスが割り当てられる。HogeService の dao フィールドも @Autowired なので同様。
DI 目的なら HogeService と HogeDao のインターフェースを用意した方がいいけど、ここでは省略。
@Autowired 可能なクラスは、@Component 派生アノテーション付きで、@ComponentScan 対象である必要がある。(もしくは xml に記述したクラス)

@Autowired 持ちクラスを手動で生成

上記サンプルのような使い方だと、@Autowired 持ちクラスが初期化されるためには、@Autowired フィールドとして生成されるか、@Controller のようにフレームワークから自動生成される必要がある。
つまり、フィールドとしてしか作れない。(@Controller もフレームワークのフィールドみたいなもの)

@Autowired 持ちクラスをフィールドじゃなく、ローカル変数として欲しい(コードで手動生成したい)ケースが稀にあると思う。
java - In Spring, can I autowire new beans from inside an autowired bean? - Stack Overflow の createAutowiredObject で簡単に生成できる。
@Component 付クラスである必要もない。

[createAutowiredObject 使用サンプル]

@Controller
public class HogeController {

    @Autowired
    private AutowireCapableBeanFactory factory;

    private <T> T createAutowiredObject(Class<T> c){
        return factory.createBean(c);
    }

    public void createAutowiredTest(){
        HogeComponent component = createAutowiredObject(HogeComponent.class);
        // HogeComponent のフィールドが初期化されていることを確認
        System.out.println(component.sub);
    }
}

public HogeComponent {
    @Autowired
    public HogeComponentSub sub;
}

@Component
public HogeComponentSub {}

使いどころ

@Component 付きクラスは、デフォルトでシングルトンである。
@Scope("prototype") を付けることで非シングルトンにすることも可能だが、親クラスも同じ @Scope を設定してやる必要がある。(シングルトンのフィールドは同じくシングルトンになる)

親クラスがシングルトンで、その内部で非シングルトンの @Autowired 持ちクラスが欲しい場合、createAutowiredObject のようなメソッドがあるといいかもしれない。
親クラスの @Scope を変えても可能だが、変えられないケースもあると思うので。

おまけ

@Scope の効果を Spring MVC で視覚的に確認できるもの

2016年1月13日

Java Stream API とチェック例外(検査例外)の相性が悪い件

久々に Java を触ることがあって、Java 8 だったので Stream API を使ってみたところ・・・
色々言いたいことはあるけど、一番の問題はチェック例外(検査例外)だと感じた。
チェック例外とは、簡単に言うと catch または throws してないとコンパイラに怒られる例外のこと。
Java 以外の言語ではほとんど採用されてないレア機能。

で、何が問題かというと、下記のようなケースでコンパイルできない。

/**
 * source にある valueType 型を返すメソッドを実行して、結果をリストで返す。
 */
@SuppressWarnings("unchecked")
public static <T> List<T> getValues(Object source, final Class<T> valueType){
    return Arrays.stream(source.getClass().getDeclaredMethods())
        .filter(m -> m.getReturnType().equals(valueType))
        .map(m -> (T)m.invoke(source)) // この行でコンパイルエラー
        .collect(Collectors.toList());
}

理由は、Stream.map がチェック例外を投げるラムダ式を引数に取れないため。

※ チェック例外を考慮した FunctionalInterface が標準 API に用意されてないこと(2016/1/12 時点)を考慮すると、ラムダ式にチェック例外を混ぜてほしくないのだろう。しかし、標準 API の中でチェック例外を投げるメソッド(上記の Method.invoke 等)は結構あるため、使う側としては混ぜざるを得ない。

検査例外を実行時例外にラップ

ラムダ式内でチェック例外をキャッチ、実行時例外にラップする。

@SuppressWarnings("unchecked")
public static <T> List<T> getValuesWrap(Object source, final Class<T> valueType){
    return Arrays.stream(source.getClass().getDeclaredMethods())
        .filter(m -> m.getReturnType().equals(valueType))
        .map(m -> {
            try{
                return (T)m.invoke(source);
            } catch( IllegalAccessException | InvocationTargetException e ){
                throw new RuntimeException(e);
            }
        })
        .collect(Collectors.toList());
}

この方法だとチェック例外を殺してしまうが、標準 API のみだとどうしようもない。
また、ラムダ式に try-catch が入り込んでソースが汚くなっている。

チェック例外を投げるラムダ式から標準 API のラムダ式に変換

lambda - How can I throw CHECKED exceptions from inside Java 8 streams? - Stack Overflow にある LambdaExceptionUtil を使う。(もしくは自作)

@SuppressWarnings("unchecked")
public static <T> List<T> getValuesRethrow(Object source, final Class<T> valueType){
    return Arrays.stream(source.getClass().getDeclaredMethods())
        .filter(m -> m.getReturnType().equals(valueType))
        .map(rethrowFunction(m ->  (T)m.invoke(source)))
        .collect(Collectors.toList());
}

rethrowFunction で、チェック例外を考慮した Function_WithExceptions から 標準 API の Function に変換している。
チェック例外を殺すことには変わりないが、ソースの見た目は最初の方法よりましになっている。
チェック例外は不要、という場合はこの方法が無難。
Stream API だけでなく、他のチェック例外無しラムダ式を引数にするメソッドにも利用できる。

後、面白いのが下記のような方法で実行時例外にラップせずにチェック例外を黙らせていること
Java の割と知られているハックらしい。

@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E {
    throw (E)exception;
}

チェック例外を投げるラムダ式を引数に取れる Stream API を使う

JeffreyFalgout/ThrowingStream · GitHub を使う。(もしくは自作)

@SuppressWarnings("unchecked")
public static <T> List<T> getValuesThrowing(Object source, final Class<T> valueType) throws Exception {
    return ThrowingStream.of(Arrays.stream(source.getClass().getDeclaredMethods()), Exception.class)
        .filter(m -> m.getReturnType().equals(valueType))
        .map(m ->  (T)m.invoke(source))
        .collect(Collectors.toList());
}

ThrowingStream.of でチェック例外を考慮したメソッドを備える Strem を作成している。
現時点(2016/1/12)で、ThrowingStream.of に指定できる例外は 1 つだけなので、複数のチェック例外がある場合は継承元を指定するしかない。
指定した例外を ThrowingStream.collect で投げてくれるので、一応チェック例外は殺してない。

愚痴

この問題については、Java 開発元がどうにかすべきだと思う。
上記のようなメソッド・クラスを用意するか、いっそコンパイルオプションにチェック例外無効を用意するとか・・・

いずれ解決方法が提供されることを祈りつつ、可能ならベター Java を使っていきたい・・・