Unknown Region

プログラムでハマったエラーとその解決方法についての備忘録メモ

【Java】[Generics]はしっかり設定して[RawType]を防ごう

[Generics]はしっかり設定して[RawType]を防ごう(大事なことなので2回ry)

以下のプログラムはコンパイルエラーになる。

注: Java8にて確認。

例: Hoge.java

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

public class Hoge {
  public static void main(String[] args) {
    Map map = new HashMap();
    Stream.of(map)
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .forEach(e -> {
          System.out.println("key = " + e.getKey() + ", value = " + e.getValue());
        });
  }
}

なぜコンパイルエラーになるかといえば、タイトルの通り[java.util.Map]にGenericsが設定されていないから。

[java.util.Map.entrySet()][java.util.Set<java.util.Map.Entry<K, V>>]を返す様になっていて、この[<K, V>]は[java.util.Map]の設定を引き継ぐ。

ただしこのケースではGenericsの[<K, V>]が設定されていないため[java.util.Map][RawType]として扱われ、[java.util.Map.entrySet()][Generics無し(RawType)][java.util.Set]を返却する。

そして[java.util.Set::stream]もまた、同じく[Generics無し(RawType)]の[java.util.stream.Stream]を返却する。

[RawType]の場合は格納される値は全て[java.lang.Object]として扱われるので、[java.util.stream.Stream][java.lang.Object]を扱うと認識されていることになる。

最後の[java.util.stream.Stream.forEach(java.util.function.Consumer)]においても[java.util.function.Consumer.accept(T t)]Genericsの[T][java.lang.Object]として認識されている。

つまり[java.lang.Object]には[getKey()][getValue()]なんてメソッドは存在しないので、コンパイルエラーになるというワケ。

 

似た様なケースは多々発生するので、[RawType]にならない様にしっかりGenericsは設定しようねということになるのだけれど、場合によってはどうしても防げないケースもある。

それは自分の管理していないモジュール、例えばParserなどで[java.lang.Class]を引数に渡して内部でキャストする様なケース

そういう場合には、仕方がないので自前でキャストしてしまうのが一番手っ取り早い。

ちなみに先ほどのコード(Hoge.java)で無理やりコンパイルエラーを消すためにキャストを仕込むと以下のコード(Fuga.java)になる。

 

Fuga.java

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

public class Fuga {
  public static void main(String[] args) {
    Map map = new HashMap();
    Stream.of(map)
        .map(map -> (Map<Object, Object>) map)
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .forEach(e -> {
          System.out.println("key = " + e.getKey() + ", value = " + e.getValue());
        });
  }
}

これでコンパイルエラーは出なくなる。

ちなみにメソッド参照で[java.util.Map.class::cast]を使いたくなるが、これだとやはりGenericsは欠落してしまうので我慢。

 

【Lua × JavaScript】Fengariのメモ

TypeScriptを弄っていたはずが、いつの間にか楽しくてFengariを弄っていた(?)ので……調べながら試したことのメモ。

fengari.io

FengariはJavaScriptで実装されたLuaVMとのこと。

ブラウザ上でLuaスクリプトを動かすことができる。

 

以下は簡単なHello Worldの例

例: index.html

<html>
<head>
<title>Hello World</title>
<script src="fengari-web.js" type="text/javascript"></script>
</head>
<body>
<script type="application/lua">
-- jsをrequire
local js = require "js"

-- windowを代入
local window = js.global

-- window.document.body.innerHTMLを書き換え
window.document.body.innerHTML = "Hello World.";
</script>
</body>
</html>

ブラウザで開くと単純に[Hello World.]と表示されるだけのHTML(笑)

[fengari-web.js]自体は事前にダウンロードしてきて同階層に置くのをお忘れなく。

ちなみにこれもまた公式に書いてある情報で、JavaScriptを使うのと同様にluaファイルを別で作成しscriptタグのsrcで指定するようにすることも可能。

 

もし本格的にこれを使って開発をすることになったら、変数のデバッグが欲しくなるかと。

ただ、JavaScriptデバッグLuaデバッグの両方が必要になって大変かもしれない。

一応、変数の内容確認に使えそうなのが以下の3つで、それぞれ動きが違うのでまとめておく。

先に言っておくと単純な文字列や数値の場合は、これら3つに大きな違いはなかった。

問題になるのはobject(table)の場合だ。

例: sample.html

<html>
<head>
<title>Sample</title>
<script src="fengari-web.js" type="text/javascript"></script>
</head>
<body>
<script type="application/javascript">
window.js_val = {"hoge": "fuga"};
</script>
<script type="application/lua">
local js = require "js"
local window = js.global

-- js_val
window.console:log(window.js_val)
window.console:dir(window.js_val)
print(window.js_val)

local lua_val = { hoge = "fuga" }

-- lua_valの内容確認
window.console:log(lua_val)
window.console:dir(lua_val)
print(lua_val)
</script>
</body>
</html>

実行結果は次の通り(consoleの内容で、少し見やすいように加工してある)

実行結果

fengari-web.js:8 {hoge: "fuga"}
                  hoge: "fuga"
fengari-web.js:8 Object
                  hoge: "fuga"
fengari-web.js:8 [object Object]
fengari-web.js:8 ƒ table: 0x23
fengari-web.js:8 ƒ n()
fengari-web.js:8 table: 0x23

パッとみた感じ、JavaScript由来のオブジェクトについては[console.log()]か[console.dir()]を使うのが良さそう。

逆にLua由来のオブジェクト(table)は、一発でconsoleに出すことは難しいのかもしれない。

 

連絡先: plugout777★yahoo.co.jp (クローラー対策のため★を@に変更してください)