授業で習わなかったJava

大学二年生の頃にjavaを授業で学んだが、その時に習わなかったjavaの使い方メモ。
javaをあまり使っていないので構文や使い方に間違いがあるかも。

目次

  • lambda
  • try-with-resources
  • nio
  • stream-api
  • optional
  • var

lambda

ラムダ式。こちらを参照しました。

Runnable runner = new Runnable() {
  @Override
  public void run() {
    System.out.println("長いコード");
  }
};
runner.run();

上記コードが下記のように書ける。

Runnable runner = () -> {
  System.out.println("短くなった!");
};
runner.run();

try-with-resources

バイバイclose()。

try () {
  ここでclose()が必要な変数定義
  変数を使う
  close()する
} catch (なんとかException) {

}

上記変数定義をtryの引数で行うとほとんどの場合はclose()がいらない!

try (ここでclose()が必要な変数定義) {
  変数を使う
} catch (なんとかException) {

}

こんな風にもかけるらしい

void foo() throw なんとかException {
  ここでclose()が必要な変数定義
  try (変数) {
    変数を使う
  }
}

nio

ファイルの操作が簡単になるらしい。
こちらのコードを参照しました。

try {
  BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(ファイルパス), "UTF-8"));
  brを使う
  close()
}

上記のコードがなんと下記のように書けるらしい。

try (BufferedReader br = Files.newBufferedReader(ファイルパス, StandardCharsets.UTF_8)) {
  brを使う
}

こんな風にもかけるらしい

Path path = Paths.get(パス);
try (Stream<String> lines = Files.lines(path)) {
    lines.forEach(System.out::println);
} catch (IOException e) {
}

stream-api

Stream APIを使うと、分かりやすくコードを書くことができるらしい。

配列やリストや連想配列等のfoo定義

for(型 bar : foo) {
  if (bar == 1) {
    System.out.println(bar);
  }
}

上記の処理を下記のように書けるようになる。

配列やリストや連想配列等のfoo定義

foo.stream()
  .filter(bar -> bar == 1)
  .forEach(bar -> System.out.println(bar));

optional

バイバイぬるぽ

Dog shibainu = getDog();
if (shibainu == null) {

}

上記の処理を下記のように書くことで強制的にnullチェック!

Optional<Dog> shibainu = Optional.ofNullable(getDog());

shibainu.ifPresent(inu -> inu.bark());

var

型の推論。

Map<String, String> map = Map.of("foo", "1", "bar", "2", "baz", "3");

Map<String, String>varで書くことができる

var map = Map.of("foo", "1", "bar", "2", "baz", "3");

備忘録

もしかして今は習ってい可能性もある。
そもそも、当時教えて貰っていたけど覚えていなかったり、聞いていなかったりしたかも。
javaのバージョンによっては使えないのもあるかも。

一年間githubに草を生やそうと思ったが251日で途絶えた話

2018/4/3から継続して草を生やしていたが、2018/12/10に草を生やすことができなかった。

github_grass.png

草を生やすことを忘れた原因

原因は主に「毎日1笑いも目指した」と「github notifyでたくさん通知を出したくなかった」の2つ。 これらの原因で草を生やすことを忘れた。

毎日1笑いも目指した

最近、毎日1笑いを目指し、youtubeでお笑い芸人の動画を深夜まで見た。 これにより、コードと向き合う時間が減り、草を生やす意識がとんだ。

github notifyでたくさん通知を出したくなかった

とあるリポジトリは、コードをコミットしてプッシュするとlineグループに通知が出るようになっていた。 草を生やすことができなかった日にコードは書いていたが、lineの通知は最小限にしたいと思い、 そのとあるリポジトリへのコミットやプッシュを潜在的に躊躇った。

githubの草について

そもそもgithubの草って何?

私の中では、githubのYour Profileに表示されるヒートマップのこと。 コミットやマージ等を行うと一日を表すマスが緑色になるため通称「草を生やす」。

どうしたらgithubには草が生えるの?

私の把握しているものだとこれらのことで草が生える。

  • デフォルトブランチへのコミットまたはマージ
  • issueを立てる
  • githubリポジトリを作成

詳しくはこちら、githubのサイト

どうして一年間githubに草を生やそうと思ったの?

  • 自慢できそう
  • 何か得られるものがありそう
  • 私の所属している研究室の先輩が一年間草を生やしていることに感銘を受けたから

どんなことをしていたの?

毎日草を生やすメリット

技術的な知見を得られる

何かを作成するための必要な技術を調べるだけでも得られるものがある。 また、実際に作成しても得られるものがある。 とにかく得られるものしかないと思っている。

義務感が出る

他に草を生やしてる人の記事を見ると、義務感が出て何のために草を生やしていたんだろうとなることがある。 私の場合は、自分の行動から生じた義務感により技術的な知見を得ることができた。 義務感により、雑なコミットがいくつも生じた。

毎日草を生やすデメリット

コミットの粒度がぐちゃぐちゃになる。

草を生やすためには、issueを立てる以外ではコードを書いてコミットしなければならない。 また、それを24時間以内に行わなければならない。 そのため、雑な感じでコミットを行うことをが多々あった。 それによるコミットのまとまりのなさが生じた。
git rebase -igit merge --squash等でコミットをまとめるのが……。

たまに辛い

私の場合は、たまにコードを書くのが辛い日がある。 時間的に余裕が取れない日が出てくると大変。

また1から

また1から始めます。今度は濃いめの草をたくさん生やしたい。

Vueでのimport HogeComponent from 'hoge-component'は<template>で<hoge-component>と書ける

概要

  • vue: 2.5.17
  • parcel-bundler: 1.9.7

インポートでimport HogeComponent from './HogeComponent.vue';と書いたときに、 コンポーネントで以下のように書かなくても、

components: {
  'HogeComponent': HogeComponent
}

以下のように書いても動きます。
HogeApp.vue

<template>
  <HogeComponent></HogeComponent>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeApp',
  components: {
    HogeComponent
  }
}
</script>

びっくりです。

ちなみにpropsでも

v-bindでデータを渡すときにHogeComponent.vueのpropsでfooBar: Stringと定義しておいても :foo-bar="ok"で渡して問題ないようです。 HogeApp.vue

<template>
  <HogeComponent
      :foo-bar="'ok'">
  </HogeComponent>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeApp',
  components: {
    HogeComponent
  }
}
</script>

HogeComponent.vue

<template>
  <div>{{ fooBar }}</div>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeComponent',
  props: {
    fooBar: String
  }
}
</script>

以下のように、HogeComponent.vueのpropsで'baz-qux': Stringと定義したときは、
同vueファイル内の<template>では<div>{{ bazQux }}</div>と書けるようです。

HogeApp.vue

<template>
  <HogeComponent
      :baz-qux="'ok'">
  </HogeComponent>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeApp',
  components: {
    HogeComponent
  }
}
</script>

HogeComponent.vue

<template>
  <div>{{ bazQux }}</div>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeComponent',
  props: {
    'baz-qux': String
  }
}
</script>

しかし、以下のコードは動きません。 HogeApp.vue

<template>
  <HogeComponent
      :bazQux="'ok'">
  </HogeComponent>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeApp',
  components: {
    HogeComponent
  }
}
</script>

HogeComponent.vue

<template>
  <div>{{ bazQux }}</div>
</template>

<script>
import HogeComponent from './HogeComponent.vue';

export default {
  name: 'HogeComponent',
  props: {
    bazQux: String
  }
}
</script>

問題

原因としてはhtmlの命名規則らしいです。以下の記事が参考になります。

まとめ

htmlタグを書くときは、ケバブケースで記入する。
まとめを書いてるときに以下の記事を見つけました。自分の記事の上位互換な気がしてやまないです。

npm publishできないと思ったら、masterブランチを修正していなかった

問題

以下のコマンドでnpmに公開する予定がダメ。
500のエラーが返ってきた。

npm publish ./


npm ERR! publish Failed PUT 500
npm ERR! code E500
npm ERR! Registry returned 500 for PUT on https://registry.npmjs.org/vue-gutter-resize

解決

npm publishするときのブランチがmasterでは無かった。
開発用のブランチだったのが問題。

1.masterにマージ
2.最新のgit tagを削除

git tag -d v0.10.0
git push origin :v0.10.0

3.ローカルをmasterブランチに切り替え
4.git tagの付け直し
5.npm publish ./

これで解決できました。

Vue.jsのコンポーネント間で値の共有をする5つの方法

やりたいこと

Vue.jsでコンポーネント間での値の共有をしたい。
親子関係問わず行えるとOK。

方法

主に以下の5つがありそう。

  • V-bind/Props/Emit
  • State Management Library (etc: Vuex, Redux...
  • EventHub/EventBus
  • BrowserStorage (etc: localStorage, IndexedDB...
  • Server (etc: firebase...

V-bind/Props/Emit

親子関係のコンポーネントだとすごい楽に値を渡せる。

parent.vueのhogeをchild.vueにv-bindで渡し、
child.vueでは、propsで受け取り、
child.vueのemitでparent.vueに値と渡し、 parent.vueのメソッドイベントハンドラhogeを更新。

ディレクト

  • Project
    • parent,vue
    • child.vue

parent.vue

<template>
  <div>
    <child
      :hogehoge="hoge"
      @hogehogeHandler='fromChild'
    >
    </child>
  </div>
</template>

<script>
import child from './child.vue'

export default {
  data () {
    return {
      hoge: 'fuga'
    }
  },
  components: {
    child
  },
  methods: {
    fromChild (msg) {
      this.hoge = msg
    }
  }
}
</script>

child.vue

<template>
  <div>
    <p>{{ hogehoge }}</p>
    <button @click="hogehogeHandler">hogehoge -> fugafuga</button>
  </div>
</template>

<script>
export default {
  props: ['hogehoge'],
  methods: {
    handler () {
      this.$emit('hogehogeHandler', 'fugafuga')
    }
  }
}
</script>

parent.vueの:hogehoge="hoge"のイコールの左側はchild.vueのprops名になり、右側はparent.vueのdataのプロパティ名が入る。

parent.vueの@hogehogeHandler='fromChild'のイコールの左側はchild.vueのemitの第一引数名になり、右側はparent.vueのmethods名または何かしらの処理が入る。

child.vueのthis.$emit('hogehogeHandler', 'fugafuga')は、第一引数にはparent.vueの@hogehogeHandler='fromChild'のイコールの左側が入り、第二引数以降には渡したい値が入る。
今回の場合はfugafugaという文字列をparent.vueの@hogehogeHandler='fromChild'を介しparent.vueのfromChild (msg)の引数で受け取っている。
なお、$emitでたくさん値を渡したい場合は以下のようにobjectにして渡している。

this.$emit('foo', {
  bar: 'yahho',
  baz: 10000,
  qux: {
    quux: 'apikey'
  }
})

State Management Library (etc: Vuex, Redux...

Vueでのコンンポーネント間で値を共有したいならとりあえずVuexを使うことがおすすめ。
筆者が他のライブラリについて詳しくないからなんとも言えないけど、VueでReduxを使うとパッとしないと思ってる(そもそもReduxをよく知らない)。
なのでここでは、Vuexを紹介。

VuexにはStateの管理方法(値の共有の仕方?)には2つの方法が存在する。
- クラシックモード - モジュールモード

今回は、モジュールモードのみ書く。(モジュールモードの方が好きだから)
ビルドは、parcelでします。
スプレッド演算子(...)を利用できるようにbabelやtypescriptでトランスパイルできるように設定しないといけない。

だいぶ複雑なディレクトリになる。
foo.vueとbar.vueで設定した値をindex.vueで見る仕組みを以下に記入。

ディレクト

  • src
    • index.html
    • index.js
    • index.vue
    • components
      • foo.vue
      • bar.vue
    • store
      • index.js
      • modules
        • baz.js

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vuex</title>
</head>

<body>
  <div id="app"></div>
  <script src="./index.js"></script>
</body>

</html>

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import App from './index.vue'
import { store } from './store'

Vue.use(Vuex)

new Vue({
    el: '#app',
    store,
    render: h => h(App)
})

index.vue

<template>
  <div>
    {{ count }}
    <foo></foo>
    <bar></bar>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import foo from './components/foo.vue'
import bar from './components/bar.vue'

export default {
  name: "App",
  components: {
    foo,
    bar
  },
  computed: {
    ...mapGetters({
      count: 'baz/count'
    })
  }
}
</script>

components/foo.vue

<template>
  <div>
    <button @click="set({ count: 1000 })">set 1000</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions({
      set: 'baz/set'
    })
  }
}
</script>

components/bar.vue

<template>
  <div>
    <button @click="set({ count: 5 })">set 5</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions({
      set: 'baz/set'
    })
  }
}
</script>

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import baz from './modules/baz'

Vue.use(Vuex)

export const store = new Vuex.Store({
  modules: {
    baz
  }
})

store/modules/baz.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  count: 0
}

const actions = {
  set ({ commit }, { count }) {
    commit("SET", { count })
  }
}

const mutations = {
  SET (state, { count }) {
    state.count = count
  }
}

const getters = {
  count: state => state.count
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

流れとしては、index.vueのcount(mapGettesのcount)でstore/modules/baz.jsのstateのcountを参照(購読?)しておく。
components/foo.vueのbutton押された場合(発行?)、
components/foo.vueのbuttonのset(mapActionsのset)で値(1000)を
store/modules/baz.jsのactionsのsetの第二引数で受け取り、
commitでstore/modules/baz.jsのmutationsのSETの第二引数で受け取り、
store/modules/baz.jsのstateに保存する。
保存するとindex.vueのcount(mapGettesのcount)は自動的に1000という値が入る。

index.vueのmapGettersでstore/modules/baz.jsのgettersの準備。
index.vueのmapGettersのcount: 'baz/count'ののkey(count)はdataのプロパティのように利用できる。
例えば、index.vueならthis.countのように利用できるようになっている。
value('baz/count')のスラッシュの左側bazはstore/index.jsのmodules: { baz }で,
スラッシュの右側countはstore/modules/baz.jsのgettersのcount。
ちなみにgetterに引数を持たせることが可能。
他に、mapGettersのstoreのmodule名を省略する書き方もある。

store/modules/baz.jsのcount: state => state.countのkey(count)がindex.vueのcount: 'baz/count'value('baz/count')のスラッシュの右側にあたる。
count: state => state.countvalue(state => state.count)は、store/modules/baz.jsのconst stateのcountを読むようになっている。

Vuexのactionsを利用しなくても構わないが、非同期処理を行いたい場合はactionsのfunctionにasync/awaitを付けて非同期処理を行うことができる
firebaseとかと連携したい場合は利用するかもしれない。

構造は違うけどサンプルリポジトリ

EventHub/EventBus

wip

BrowserStorage (etc: localStorage, IndexedDB...

wip

Server (etc: firebase...

wip

firefoxのdrag, dragendイベントはclientX, clientYの値が0になる

環境

firefox: 61.0.1 (64-bit)

問題

ここのサイトの下の方のdemo
以下のdragイベントの'event'の中身を見ると
document.addEventListener("drag", function( event ) {
clientX, clientYの値が0になっている。

他のブラウザ

chromeだとちゃんとclientX, clientYが取得できる。

対応状況

ここを見ると9年前から話題になっている。

解決案

jQuery UI draggable eventを使う
ここのjsfiddleでdraggableのdragイベントを見る
drag event で取得した中身のoriginalEventにはclientX, clientYがfirefoxでも入ってる!!!
だけどdrag eventを、mousemove eventで補っているっぽい

vueのメソッドイベントハンドリングで引数にeventと任意の引数を渡す

やりたいこと

vueのtemplateでイベントハンドリングするときに、引数でeventとその他の引数もメソッドへ渡したい。

方法

自分は以下の二通りを見つけた。

<button @click="handler($event, foo)"></button>
<button @click="e => { handler(e, foo) }"></button>

サンプル index.vue

<template>
  <button @click="handler($event, foo)"></button>
</template>

<script>
export default {
  data () {
    return {
      foo: 'bar'
    }
  }
  methods: {
    handler (event, foo) {
       console.log(event, foo)
    }
  }
}
</script>
<template>
  <div>
    <ul>
      <li v-for="(word, index) of words" :key="index"
        @click="e => { handler(e, word) }">
        {{ word }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      words: ['a', 'd', 'c', 'd', 'e']
    }
  },
  methods: {
    handler (e, word) {
      console.log(e, word)
    }
  }
}
</script>