きしだのはてな このページをアンテナに追加 RSSフィード

2017-06-09(金) ラムダのオブジェクトはどう作られるか

[]ラムダのオブジェクトはどう作られるか 06:20 ラムダのオブジェクトはどう作られるかを含むブックマーク

ラムダは匿名クラスのシンタックスシュガーだとか言われますけど、オブジェクトの作られ方が違いますね。

というのを検証してみます。

(jdk1.8.0_112で動かしています)


ループの中でhogeにラムダを渡して、hogeでオブジェクトを表示します。

まず匿名クラスを使ったコード。

public class LambdaObj {
    public static void main(String[] args) {
        for (int i = 0; i < 2; ++i) {
            hoge(new Runnable() {
                @Override
                public void run() {
                }
            });
        }
    }
    
    static void hoge(Runnable r) {
        System.out.println(r);
    }
}

実行するとこう。

myproject.LambdaObj$1@15db9742
myproject.LambdaObj$1@6d06d69c

明確にnewしてるので、毎回違うオブジェクトが渡されています。


これをラムダにしてみます。

public class LambdaObj {
    public static void main(String[] args) {
        for (int i = 0; i < 2; ++i) {
            hoge(() -> {});
        }
    }
    
    static void hoge(Runnable r) {
        System.out.println(r);
    }
}

実行すると、こう。

myproject.LambdaObj$$Lambda$1/834600351@548c4f57
myproject.LambdaObj$$Lambda$1/834600351@548c4f57

オブジェクトが使いまわされていることがわかります。

ラムダと匿名クラスは違うということですね。

バイトコードとしては

private static void lambda$main$0() {
  //ラムダの中身
}

のようなメソッドが生成されて、invokeDynamicをよんでラムダオブジェクトを取ってくるようなコードが生成されます。このinvokeDynamicでいろいろやられているということですね。


めでたしめでたし。


ではなくて、もうちょっと調べてみます。

ラムダの中で、外側のローカル変数であるargsを使ってみます。

public class LambdaObj {
    public static void main(String[] args) {
        for (int i = 0; i < 2; ++i) {
            hoge(() -> {
                String[] a = args;
            });
        }
    }
    
    static void hoge(Runnable r) {
        System.out.println(r);
    }
}

そうすると、こう。

myproject.LambdaObj$$Lambda$1/834600351@1fb3ebeb
myproject.LambdaObj$$Lambda$1/834600351@548c4f57

この場合は匿名クラスに展開されるのかなーと思ったけど

private static void lambda$main$0(String[]) {
  //ラムダの中身
}

のようなメソッドが定義されますね。


外側のローカル変数を使わない場合は簡易なオブジェクトを使っていて、外側のローカル変数を使う場合は引き渡すローカル変数のコピーをもったオブジェクトを渡さないといけないので毎回オブジェクトを生成してる、とかですかね。

2017-06-04(日) A-ONEサーキットでレーシングカートしてきたメモ

[][] A-ONEサーキットでレーシングカートしてきたメモ 21:17  A-ONEサーキットでレーシングカートしてきたメモを含むブックマーク

行ってきた。

アクションカメラで撮ってみたので、次回はこうやろうというメモ。


コース

Aパターンの左回りです

f:id:nowokay:20170604205714p:image

http://www.rk-a1.com/coursemap.html


まがりかた

1,2コーナー

なんか、他の動画をみてると、インベタで行ってるので、次に試してみる。

f:id:nowokay:20170604205713p:image

ここでアクセルを抜く

f:id:nowokay:20170604205712p:image


2コーナーまで踏みっぱなしの場合は看板手前でアウトに。

看板手前の林をめざす

f:id:nowokay:20170604205703p:image

ここから2コーナーのインを目指す

f:id:nowokay:20170604205704p:image

2コーナーは角が取れてるので、それにそって行く感じ

f:id:nowokay:20170604205705p:image


3,4コーナー

なんも考えてない

f:id:nowokay:20170604205706p:image

f:id:nowokay:20170604205707p:image


5コーナー

小屋の前のクッションを目指す

f:id:nowokay:20170604205708p:image


6コーナー

アクセルちょっと抜く

f:id:nowokay:20170604205709p:image

ななめに横切るイメージ

f:id:nowokay:20170604205710p:image


7コーナー

次回考える

f:id:nowokay:20170604211151p:image


8コーナー

右によりすぎず、NGKの看板に抜ける

f:id:nowokay:20170604205711p:image

2017-05-28(日) Amazonが1巻目実質92%引きセールをやっている

Amazonが1巻目実質92%引きセールをやっている 04:23 Amazonが1巻目実質92%引きセールをやっているを含むブックマーク

ポイントが92%ついてくるので、実質92%引きです。

1巻完結のとかだと とてもいいです。ポイントがつくまで時間がかかるみたいなので、ある程度 間をおいてから買うほうがいいです。

これで知ったんだけど、ポイントってKindle購入だと勝手に使われるんですね。


ということで、1巻完結のマンガを10冊ほど。

解説は しない。

※ 月曜のうちに終わっていた



ヘウレーカ (ジェッツコミックス)

ヘウレーカ (ジェッツコミックス)









トラックバック - http://d.hatena.ne.jp/nowokay/20170528

2017-03-31(金) Javaの難しいところ

[]Javaの難しいところ 23:50 Javaの難しいところを含むブックマーク

Javaをプログラム未経験者に教えるときの話。

細かいところまでちゃんと理解するための難しさではなくて、とりあえず頻出コードが読み書きできるまでの難しさの話です。細かいところまでの理解、どの言語も難しいので。

あと、ここではプログラム自体の難しさは別の話、ということで。

で、Javaには難しいところが結構あるんですけど、難しいのをひとことでいうと「昔の事情や歴史的経緯により、が多い」ところです。


プログラムを教えるときに何が難しいか

たとえばpublic static void mainを書くとか、おまじないが多いとか記述量が煩雑とかは、ツールで対処可能で、ツールで対処可能というのは機械的に慣れればいい部分なので、そこまで問題にならないと思います。

あと「おまじないを減らしたい」というのは教える側のこだわりであって、理解しやすさとは別で、そのおまじないがどういうときに必要かというところさえ理解できればいいと思います。ないほうが楽ではあると思いますけど。

ツールの導入もインストーラダウンロードして「次へ」を押しまくるのは、そう問題じゃないと思われ。


つまり「慣れ」ではなくて「理解」が必要なところに難しさがあると思います。

そういう、プログラムの学習が難しくなる要因として、プログラム自体の本質的は難しさとは別に、大きく2つ、次のようなものがあると思っています。

  • 同じことを実現するために、異なる2つの機能がある
  • 暗黙のルール

同じことを実現するために、異なる2つの機能がある

シンタックスシュガーは除き、同じことを書くときに2つの選択肢があるのは結構つらいです。

Javaが難しい部分の多くは、こちらになると思います。

  • classとinterface
  • intとInteger(基本型とラップクラス)
  • Listと配列
  • forとforEach
  • DateとLocalDateTime

まあ、最近はインタフェースをimplementsする機会は減っているし、自分で定義する機会もあまりないので、必要になったときには こう書け、って感じでいい気がします。型として使う分には、クラスと区別する必要はないし。

forとforEach、DateとLocalDateTimeも、好みやシチュエーションの問題ではある。


ただ、基本型とラップクラスや、Listと配列は、普通にコードを書くときについてまわるし、Streamを使うときには意識する必要があるので、ちょっと困る。

Streamがなければ、「配列は使わない」「ラップクラスはGenericsで指定するとき用」くらいの雑さで回避することができたのだけど。

Valhallaでどうにかなりそうなのが救い。

暗黙のルール

書いたコードの裏でいろいろ行われて、知らなければ書けないとかエラーが意味わからなくなるとか、そういうの。

Javaの場合はコンストラクタとラムダ。staticメンバとインスタンスメンバ。デフォルトスコープ。


コンストラクタの場合、暗黙でsuper()が呼び出されるやつと、引数ありのコンストラクタを定義するとデフォルトコンストラクタがなくなるののコンボで、意味不明なコンパイルエラーがでるのが罠でした。

class Foo{
  Foo(int a) {}
}
class Bar extends Foo{
}

で出るコンパイルエラー。

最近は継承使う機会も減っているので、逃げれる気はする。


staticメンバとインスタンスメンバもつらいな。まあ、入門時にはぜんぶ非staticで。

スコープ(可視性)も最初はあんまり意識しなくてもいいか。


しかし、ラムダ、おまえだけはだめだ。

未定義メソッドが1つのインタフェースに対してそのメソッドのシグネチャを使って、引数ひとつのときにはカッコや型が省略でき・・・、というの。

まあ、現実的に出てくるのはFunction、Runnable、Consumer、Supplierくらいなので、そこだけ押さえて、あとはMap.forEachみたいなのは「こう書けますよ」くらいでいいのかな。

いけるかな。

というか、そう逃げるしかない気がするな。

2017-03-20(月) Java9で小の月を列挙する

[][]Java9で小の月を列挙する 04:55 Java9で小の月を列挙するを含むブックマーク

jshell> LocalDate.of(2017,1,31).datesUntil(LocalDate.of(2018,1,1),Period.ofMonths(1)).
   ...> filter(d -> d.getDayOfMonth() != 31).
   ...> map(LocalDate::getMonth).
   ...> toArray()
$163 ==> Object[5] { FEBRUARY, APRIL, JUNE, SEPTEMBER, NOVEMBER }

あ、ふつうにこれでよかった

jshell> Arrays.stream(Month.values()).filter(m -> m.maxLength() != 31).toArray()
$165 ==> Object[5] { FEBRUARY, APRIL, JUNE, SEPTEMBER, NOVEMBER }
トラックバック - http://d.hatena.ne.jp/nowokay/20170320