人生、気合いと具合 - blog

2016年12月

この記事は、JavaFX Advent Calendar 2016の21日目です。
昨日はHASUNUMA KenjiさんのJavaFX の TextField に入力補完を付けてみるでした 

去年のAdvent Calendarで、ListViewの扱いについて書きました。
ScalaFXの実装方針との兼ね合いで、ListCell#updateItemをオーバーライドするというCell描画の方式がうまくいかない、という内容です。

今年の記事を書くにあたって、このあたりについてもう一度調べてみたら、ScalaFXのGitHubに、issueがあがっていたので、今年は一年越しの続編として、これについて書いてみます。

まず、 JavaFXで、CellFactoryを設定するメソッドは以下となります。
public final void setCellFactory(Callback<TreeView<T>,TreeCell<T>> value)
ScalaFXでは以下。
def cellFactory_=(v: (TreeView[T]) ⇒ TreeCell[T]): Unit

どちらも、TreeViewを引数として受けて、描画処理を実装したTreeCellのインスタンスを返すコールバックを設定します。
しかし描画処理自体は、TreeCell#updateItem をオーバーライドして実装するので、ScalaFXのクラスだけでやろうとするとうまくいきません。上記のissueにも例がありますが、ちゃんとやろうとすると結局、ScalaFXのcellFactoryでも、JavaFXのTreeCellを使うことになってしまいます。
このへんは去年の記事で書いたとおりです。(私の記事はListCellを使って、継承したクラスを別に定義。issueの例ではTreeCellをメソッド内で直接newしてますが、JavaFXのクラスを使ってupdateItemメソッドをオーバーライドしなきゃならない、という意味で言いたいことは一緒です)

で、issueでは、cellFactoryメソッドのシグネチャを変えるのがいいんじゃね?という内容になってます。
def cellFactory_=(u: ((TreeCell[T], T, Boolean) => Unit))

というわけで、試しに実装してみました。
※FactoryなのにUnitなのがどうかなーと思ったので、「cellRenderer」にしてます
※issueではTreeCellですが、去年のコードを一部再利用している関係でListCellです

●ListViewの代わりに使うクラス
package com.bugworm.advent2016

import javafx.util.Callback
import javafx.scene.{control => jfxsc}

import scalafx.Includes._
import scalafx.scene.control.{ListCell, ListView}

class NewListView[T](override val delegate: jfxsc.ListView[T] = new jfxsc.ListView[T])
  extends ListView[T]{

  private var renderer_ : (ListCell[T], T, Boolean) => Unit = _
  def cellRenderer = renderer_
  def cellRenderer_=(r: (ListCell[T], T, Boolean) => Unit): Unit ={
    renderer_ = r;
    cellFactory() = new Callback[jfxsc.ListView[T], jfxsc.ListCell[T]] {
      override def call(param: jfxsc.ListView[T]): jfxsc.ListCell[T] = {
        new jfxsc.ListCell[T]{
          override def updateItem(item: T, empty: Boolean): Unit ={
            super.updateItem(item, empty)
            (item, empty) match {
              case (null, _) | (_, true) => {
                setText(null)
                setGraphic(null)
              }
              case (item, empty) => renderer_.apply(this, item, empty)
            }
          }
        }
      }
    }
  }
}

●使用例
package com.bugworm.advent2016

import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.Label
import scalafx.scene.layout.VBox

object CellSample extends JFXApp{

  stage = new PrimaryStage{
    scene = new Scene(new VBox(
      Label("Cell Factory Test"),
      new NewListView[Book](){
        prefHeight = 100.0
        items = ObservableBuffer(
          new Book("ゴルゴ13", "さいとうたかを"),
          new Book("数学ガール", "結城浩"),
          new Book("三国志", "吉川英治"),
          new Book("ガラスの仮面", "美内すずえ"),
          new Book("哭きの竜", "能條純一"),
          new Book("傷だらけの天使たち", "喜国雅彦")
        )
        cellRenderer = (cell, item, empty) => {
          cell.text = item.title + " [" + item.author + "]"
        }
      }
    ))
  }
  stage.show()
}

ListViewの代わりのクラスはJavaFXとScalaFXが入り混じって結構面倒な実装になっていますが、使用例の方はJavaFXのクラスを使う必要が無いので、割といい感じなんじゃないかと思います。
 

はじめに

この記事は、システムエンジニア Advent Calendar 2016の14日目です。
いわゆるコーディング規約について、というかコーディング規約が、出来上がるコードにあたえる影響について、ここ数年考えていたことの一端です。
なお、具体的な規約の内容の話ではなく、抽象的な話が多めです。

たとえば

コーディングミスを原因とする障害があった場合に、再発防止としてコーディング規約に注意点を追記しておく、みたいな結論になることがあります。
まあ、Javaでよくあるやつで例えれば、
障害:+によるStringの連結をループ内でやっちゃったから超遅くなった
対策:ループ内でStringつないでく時はStringBuilder使え、って規約に追記しよう
みたいな感じですね。
気持ちはわからなくはないですし有効な対策となることもありますが、続けていくとコーディング規約がどんどん肥大化していくわけです。

もんだい

不思議なことに「こうやってコーディング規約を充実させていけば、誰でもよいプログラムが作れるようになるはずだ」と考える人もいます。(偉い人に多い)
果たしてそうでしょうか。
プログラマならわかってもらえると思いますが、コーディング規約があまりに肥大化するとそもそも読む気にならないし、気になったときにちょっと確認する、とかもやりづらくなります。
また、規約で縛るというのは「適切な実装がどれなのか判断しなくてよくする」ことでもあります。これは、レアケースを見抜いて「多数派ではないが適切な実装」をする、という選択肢を封じてしまいます。
これらはコードの質についてマイナスとなるでしょう。

こうさつ

チームで開発する場合、コーディング規約はあったほうが確実にいいと思います。特に、ネーミングやフォーマットに関しては必須と言えるでしょう。
ただ、禁止事項や推奨事項の類についてのコーディング規約を充実(肥大化)させていく、というのは、行く末がイマイチであるのは間違いなさそうです。
とはいえ、さまざまなシチュエーションに対応した規約を、「ほどほどのボリューム」でカバーできるとは到底思えません。

けつろん

誰でも「よいコード」を生み出せるようなコーディング規約、というのは現実的ではありません。
コーディング規約の役割は「よいコード」を生み出すことではなく、「最悪の結果を回避する」ということだと考えるのが良いと思います。
ざっと読み流せるくらいのボリュームで、残念なプログラマがやらかすのを回避しつつ、チョットデキルプログラマの邪魔をしない、そんなコーディング規約が理想でしょう。

こんな二人
私は拝承プログラマ、妻は主婦業の傍ら放送大学で学ぶ女子大生(?)です。
バンドサークル(私:ベース、妻:ボーカル)で出会い、5年くらいの遠距離恋愛(北海道~神奈川)を経て入籍。結婚生活14年目に突入しました。

日常
ケンカらしいケンカはほとんどなく、あるとしたら私がなんかやらかして一方的に怒られるパターンです(笑)
妻は年下ですが姉みたいな存在で、一緒に生活しているといろいろ教えてもらえます。まあ私自身が非常識すぎるという話もありますが...

大好きなので...
朝、出かける前は必ず行ってきますのちゅー。
作業中にちょっと一息入れたいときとか、妻に後ろからくっついて「にゃー」とか「大好きー」とか言ったり。
というか、何かにつけてほっぺにちゅー、という感じですかね。にゃー。


※なお、普段は「ヨメ」という表現を使うことが多いのですが、「妻・夫を愛してるITエンジニア Advent Calendar 2016」なので、今回はそれに合わせて「妻」という表現に統一しています。

この記事は Java Puzzlers Advent Calendar の8日目です。

・問題
最近は問題なくマルチバイト文字を含んだファイルを読み込めるようになった java.util.Properties ですが、昔はnative2ascii使ったりで面倒でした。
以下は、仕事で実際に遭遇したコードを元にしたものです。仕様的にはダメなわけですが、さて、実際に実行したら結果はどうなるでしょうか。

●プロパティファイル(Shift_JIS)

programmer=十把一絡げ

●プログラム

package com.bugworm.advent2016.puzzlers;

import java.io.InputStream;
import java.util.Properties;

public class MultiByteCharacterProperties{

    public static void main(String... args)throws Exception{
        Properties properties = new Properties();
        try(InputStream in = 
                ClassLoader.getSystemResourceAsStream("test.properties")){
            properties.load(in);
        }

        String value = properties.getProperty("programmer");
        String shift_jis = new String(value.getBytes("ISO8859-1"), "Shift_JIS");
        System.out.println("programmer は " + shift_jis);
    }
}

(1) 「programmer は 十把一絡げ」と出力される
(2) 実行時例外
(3) 「十把一絡げ」の部分が文字化けする






解答

(3) 「十把一絡げ」の部分が文字化けする

解説

この場合は文字化けするのですが、実は、たいていのケースではちゃんとマルチバイト文字を読み込めてしまいます。
しかし、上記の「十把一絡げ」はダメなのです。

「十把一絡げ」は、Shift_JISだと 「8F 5C 94 63 88 EA 97 8D 82 B0」となります。 
2バイト目の「5C」がくせものです。
単独で見るとこれは「\」になります。最初にPropertiesクラスが読み込む際にはShift_JISとして意識していませんので、これは実際に「\」として読みこまれます。
プロパティファイルでは「\」はエスケープ文字なので、「5C 94」部分がエスケープとみなされます。ただし「94」はエスケープとして特に意味がないのでそのまま「94」として解釈されます。
したがって読み込んだ結果を getBytes("ISO8859-1") すると「8F 94 63 88 EA 97 8D 82 B0」です。(5Cがなくなる)
なので、これをShift_JISとして文字列にすると、「8F 5C」が「諸」、3バイト目(元は4バイト目)の「63」は半角「c」なので、実行結果は「programmer は 諸c一絡げ」と表示されます。

ちなみに、 「十\把一絡げ」として、5Cを重ねてやれば、「8F 5C 5C 94 63 88 EA 97 8D 82 B0」となり、読み込み時に5Cが残る(5C 5Cをエスケープとみなして、5Cとして読み込まれる)ので、 結果的に「十把一絡げ」になります。
 

このページのトップヘ