謹賀新年
あけましておめでとうございます
今年もよろしくお願いいたします。
2024年01月01日 独り言
Jsoupの使い方がよくわかんない
このWebページを生成するプログラムをC++11以前の古いC++で作っていたのをjavaでjsoupを使って書き換えようという気分になって書き換え始めたのだけれど、jsoup自体初心者なので細かい問題にぶつかってばかり。
最初はjsoupでnodeとかdocumentとかelementとかの使い分けがわからないところからスタートしているのでjavadocっぽいドキュメントを頑張って読んでいました。
その後はxmlヘッダーやドキュメントヘッダーの付け方に悩み、今は改行の付け方に悩んでいます。
一応このページはXHTML 1.0 Strictで作っているので、改行は<br />なのですが、appendElement("br /")だと閉じタグが生成されて<br /></br />になってしまうんですよね。
appendElement("br")ならばならば閉じタグが作られず<br>だけが生成されるのに。
もしかしてjsoupでこれはxhtmlだとかhtml5だとか教えることができて、その辺の設定ができるとうまいことやってくれるのかしら?
(追記)やっとわかった。XHTMLだから、jsoupをhtmlモードではなくxmlモードで動かさなければならない模様。
doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
してからdoc.outerHtml();すれば良いんだ!
とりあえずXHTMLの骨組みはこんな感じで生成できそう
doc = new Document("");
XmlDeclaration xmlDecl = new XmlDeclaration("xml", false);
xmlDecl.attr("version", "1.0");
xmlDecl.attr("encoding", doc.charset().displayName());
DocumentType docType = new DocumentType("html",
"-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
doc.appendChild(xmlDecl);
doc.appendChild(docType);
Element html = doc.appendElement("html");
html.attr("xmlns","http://www.w3.org/1999/xhtml");
html.attr("xml:lang","ja");
html.attr("lang","ja");
Element head = html.appendElement("head");
head.append("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\" />");
head.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
head.append("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />");
doc.title("MyPage");
Element body = html.appendElement("body");
Element ddd = body.appendElement("div");
ddd.appendChild(new Comment("Comment Node"));
ddd.appendChild(new TextNode("TextNode"));
ddd.appendElement("br");
ddd.appendText("&");
doc.outputSettings().indentAmount(0);
doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
doc.outerHtml();
誰かのお役に立てれば。
2024年01月13日 プログラミング雑談
VSCodeでmavenでJUnitとかjacocoとか
割と最近までVisualStudioでC++の人だったのでjavaとかVSCodeとか、何かしようとするたびに壁にぶつかる今日この頃。
ググりまくりなのだけれど、右も左もわからない初心者なのでググるキーワードが多分不適切なのでしょう。全然情報が見つかりません・・・(涙)
VSCodeでExtension Pack for JavaとかMaven for Javaを入れて、簡単なコードを書いて、JUnitのテストコードを書いて実行してみてます。
コマンドパレットで"Maven Execute Commands..."で"install"を実行すると多分実行jarを作ってくれて、JUnitのテストを実行してくれて、カバレッジまで測ってくれるようです。ステキ。
そしたら間もなく
[WARNING] Rule violated for method com.segu.Index.addText(org.jsoup.nodes.Element, java.lang.String): complexity total count is 7, but expected maximum is 5
とか言われ始めました。
悪かったね! どうせ私のコードはスパゲッティだよ! とか思いながら、とりあえずcomplexityのmaximumを8とかにすれば良いんでしょ?ってことで、VSCodeのsettings.jsonとかに何か書けばいいんだろうなと思いながらググること何時間?。結局解決策がわからず、
[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.4:check
で"install"がエラーになってから手動でJUnitのテストを実行してました。
pom.xmlを見ると
<maximum>${jacoco.unit-tests.limit.method-complexity}</maximum>
という行があったので、method-complexityというパラメタ名でググったけれどわからず。
あきらめてcomlexityのチェック行をpom.xmlから全削除するという暴挙に出てERRORを回避して何日か過ごしました。
で、
別件でpom.xmlを見てたら
<jacoco.unit-tests.limit.method-complexity>5</jacoco.unit-tests.limit.method-complexity>
なんて行があるではないですか。なんだ、pom.xmlの中で上限値を設定してたのかよ!ってことで、ここで上限値を8とかにしたらWARNINGもERRORも消えてすっきり
で、さらに私の前に(多分客観的には低い)壁が出現するわけですよ
JUnitのテストはlog4jで何のテストを実行したかログを出力したいので、log4j2.xmlが見えるようにクラスパスを設定したいのだけれど、どうやったら設定できるかわからずに半日ググった結果、このサイトを見つけました。
いや、見つけたってなんだよ。VSCodeのMavenプラグインが設定してくれたpom.xmlにmaven-surefire-pluginって書いてあんだから、surefireのオフィシャル見に行くのは当然だろ!って気もしますが、わかんないことばかりでどこを見に行って何を読めばいいかわかんないんですよ....と言い訳しておきます。
私はプロジェクトのルートにlog4j2.xmlを置いているのでpom.xmlに次のように書けばよいみたいです。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>./</additionalClasspathElement>
</additionalClasspathElements>
</configuration>
</plugin>
数日経つと忘れちゃうんだろうなという事で記録を残してみます。備忘録かよっ
2024年01月20日 プログラミング雑談
javaで正規表現
このページをテキスト形式からhtmlに変換するプログラムはC++で2009年に書いたものです。
これをjavaでjsoupを使って書き換えようと思い始めて多分2週間。
機能実現検証用の試作が動きました・・・。
もう若くないので夜更かしはできないし、平日昼間は仕事だし、このwebページをjava版の変換プログラムで作るのは2月に入ってからかなぁ。
秀丸の置換とかsedとかgawkで正規表現を便利に使っていますがjavaの場合のやり方を少しメモ。
Pattern pattern = Pattern.compile("^[ \t]*&([^:]+):") ;
Matcher matcher = pattern.matcher(inLine);
if(matcher.find()) {
if(matcher.group(1).equals("end")) {
とかすると、"&end:"が検出できる模様。Patternの行からfindの行までは1行で書けるので、それなりにすっきり書くこともできるのですね。
はまったポイントは数字とマッチする"\d"は"\"自身がエスケープ文字なので"\\d"と書かねばならないとか、find()まで実行しないとgroupが使えないところですかね。
2024年01月21日 プログラミング雑談
java版のこのwebページ生成ツール 仮運用開始
正月が明けてからテレビアニメも見ずにプログラムを書いていました。
タイトルの通り、今日からこのwebページのhtmlはjavaで作り直したプログラムで生成を開始しました。
ページの見た目はcssファイルの方なのであまり変わっていないはず。個々のアーティクルへのリンクは極力従来通りに生成できるようにコードを書いたので、htmlの方もhtml自体をテキストエディタなどで見比べない限り(見比べても)わからないのではないかな。
もちろん何もないところからwebページのhtmlが出てくるわけではないので原稿があります。原稿はテキストファイルです。今回java版を作って従来の原稿を流すまで気が付きませんでしたが、これまでShift-JISファイルを使っていましたが、今回はUTF-8 BOM無しのテキストファイルを原稿の文字コードにしました。
その他、原稿のリンクや箇条書きなどはマークダウン風の記法にしました。今まではいくつかの独自記法でコード記載ブロックを切り分けていましたが、その他は原稿にhtmlタグを書くというweb黎明期でもほとんどはやらなかったであろう地味な作業をしていましたが、これももう不要です。改行のbrタグすら手書きだったものなぁ。
今回取り入れたマークダウン風の記法は
- 箇条書き
- 行末スペース二つで改行
- リンク
- イメージ挿入
- コード記載ブロック
- 見出し
あたりです。
いままでコード記載ブロックの処理にバグがあって空行が表示されていませんでしたが、これも表示されるようになったはず。しばらく気が付きませんでしたが、気が付いた時に空行ではなくスペース一つ入力して回避してたりしました。
htmlのエスケープ文字もjsoupが自動で変換してくれるはず。
コーディング上は、15年前のC++版でも途中まで単体テストを入れていましたが、コーティングが進むにつれてメソッドの複雑度が上がってテストを書くのを断念してしまっていました。それだけでなく15年の歳月の間に流行りのc++テストツールが世間的に交代してしまったようで、その意味でもテストを書いて動かし続けるのが困難な状態でした。
今回はメソッドのコード複雑度(サイクロマチック)5以下でここまで作り切っていますので、今度こそ単体テストを後付けで作っていけるはず。
たくさんコードを書いたようなつもりだったけれどかぞえチャオで数えたら1,500ステップもなかった
2024年01月29日 プログラミング雑談 このページのリフォーム
ページのレイアウトをいじってました
ページの見た目をマイナーチェンジしました。
パソコンで見たときに、中途半端なウインドウ幅にしたときにレイアウトが崩れるのを放置していましたが、私のところではちゃんと表示するようにしたのと、スマホで見たときに少し見やすい感じを狙ってみました。
今回いじったのはcssファイルが中心で、ブラウザのキャッシュをクリアしないと変更が反映されないかも。
PC(firefox、chrome)とChromeBook(chrome)ではまあ想定通りの表示になったけれど、スマホのchromeでなぜか右に余白ができて右スクロールができてしまうのがちょっと気になる。あとはスマホのchromeで縦スクロールがカクカクする感じ。私の今のスマホ、5年位経ってたっけ・・・
(追記)スマホで右スクロールになってしまう件、ログ出力の英文がブラウザからは一単語に見えて改行できず、長い長い1行で表示していたためだったようです。cssファイルに
word-break: break-all;
って書いたら直りました。
2024年02月03日 このページのリフォーム
サイクロマチック数 max 5の世界
久しぶりにプログラムを書くといろいろ勉強になりますね。
今回の一番の収穫はメソッドのサイクロマチック数をmax 5で作るのも良いものだ、という事を実感したことかもしれません。
最初はmavenの環境をチュートリアル見ながら構築したらデフォルトでそのような設定になっていたというだけなのですが、これがデフォルトという事は何か意味があるに違いないと思ってmax 5縛りで作ってみました。
最初に影響が出たのがswitch文。こんなの使うとあっという間にサイクロマチック数5を超えてしまいます。ファクトリーメソッドで処理を切り分けるようにしました。ファクトリーメソッドでもファクトリー部分で分岐が出ないようにArrayListとかに選択肢を詰め込んでおいてget(key)で探したりforeachで探したり。
次にif文の使用。メソッドの責務をシンプルにして、メソッドの上から下まで条件分岐なしでいかに流しきるか考えるようになりました。今回作っていたプログラムは、テキストファイルを読み込んでhtmlに変換して書き出すというシンプルなコマンドラインプログラムでした。メソッドの入り口で「入力ファイルを確認する」みたいなメソッドでチェックして、NGならエラーリターンし、その後の処理は余計なことは考えずに上から下まで一気に流す、みたいなスタイルになっていきました。
そのうちメソッドのサイクロマチック数 max 5はまあ普通に守れるようになってきましたが、次にクラスでmax 20という条件で引っかかるようになりました。メソッドが1つあればサイクロマチック数も最低1あるという数え方ですので、クラスのメンバー変数がいくつかあってsetter、getterを書き始めるとたちまち超えます。setter、getterは今回はあまり書かないで作ってみました。これが正しい対処法かどうかわかりませんが、
それよりも「もし入力ファイルが無かったら」はFileReaderクラスの責務、「もし入力ファイルの記載が間違っていたら」は処理するクラスの責務、みたいにクラスの責務を整理して、一つのクラスで処理しなければならないメソッドを減らすことに注力してました。
テキストファイルを読み込んだり、htmlをファイルに書き込んだりするのはhtmlを生成するクラスの責務ではないよね、ということで、ファイル読み書きは別クラスに切り出したり。
おかげで単体テストコードも書きやすいです。まだあまり書けていませんが、これまでコードの構造のせいでテストが書きにくいといった事には出くわしていません。
まだ単体テストを一通り書いていないのにこんなことを言うのもなんですが、単体テストってプログラマーの意図通りコードが書けているかどうかのテストなのだなぁと実感していました。単体テストが通っているのに出力されたhtmlファイルが意図通りではないことが頻発しています。これはplaywrightみたいなツールで結合テストするしかないのかもしれないですね
そうそう、サイクロマチック数とは関係ないかもですが、今回は(今回こそ)設計書をちゃんと書くぞと(まだ)思っています。DoxygenとかplantUMLとか使ってちまちま書いています。
私が飽きるのが先か、テストや設計書を作り切るのが先か、どうなるんでしょうね?
2024年02月04日 プログラミング雑談
jsoupで最初つまづいたところ
今度のお休みに書こうと思っていることをメモ
jsoupで私のwebページを書こうとして結構ずっと混乱していたのがappendChild()とappendElement()の使い方。
Element ddd = new Element("body");
ddd.appendElement("div").attr("name", "segu");
と書くことはできるけれど
Element ddd = new Element("body");
ddd.appendChild(new Element("div")).attr("name", "segu");
と書くと多分思ってたのと違う結果になる。
前者は<body><div name="segu">で
後者は<body name="segu"><div>になるはず。
jsoupのAPIリファレンスに書いてある通りだし、今考えるとこれが当然の挙動なのだけれど、その辺が理解できるまで思ったようなhtmlにならなくてだいぶ混乱してました
2024年02月08日 プログラミング雑談
rdfファイル生成もjavaに移行
テストはあまり書けていませんがrdfファイル作成もjavaのプログラムに書き換えました。
書き換えたと言ってもC++版のコードは見ていないのですけど。今回のjavaプログラム化は結局C++のコードは全然見ないで作ってしまいました
2024年02月10日 このページのリフォーム
xhtml 1.0 strict
プログラミングというよりこのページのリフォームの話題かな。
何度か言っていますが、このページはxhtml 1.0 strictで作っています。このたびページの見た目の不具合も解消したいなと思ってcssファイルの方も見直しました。ポイントとしてはスマホ重視に切り替えた感じです。
ついでにhtmlとしてあるべき感じにしたいなぁと、htmlの入門サイトで<div>ばっかりじゃなく<nav>とか<main>とか<header>とか使った方が良いと書いてあったので直しました・・・。そしたらxhml 1.0 strictのバリデータにErrorだって言われてしまいました。
あとはサイト外のページへのリンクにtarget="_blank"使ったらこれもダメ。
strictの道は厳しい
2024年02月11日 このページのリフォーム
3日なんてあっという間
jsoupについて何か書こうと思っていたけれど、gradleとかgroovyとかkotlinとか調べてたら土日が終わって、sonarQubeとかいうのの存在を知って使い方を調べて今回書いたコードをみてもらったら指摘がドバドバあって、月曜も終わってしまいました。
2024年02月12日 プログラミング雑談
javaの本
C++がある程度わかってきたら、書籍 プログラミング言語C++で勉強しなおすとすごくためになると思っています。
同様にjavaの場合にプログラミング言語Javaを読めばいいのかというと、なんか違う気がします。おとといの土曜まで知りませんでしたが、この本はJava 1.5までの内容しか書かれていないそうじゃないですか。せめて1.8のラムダとかメソッド参照とかstreamとか書かれていないといまどきのプログラミング言語として物足りないと思います。どおりでこの本をいくら調べてもメソッド参照について書かれていないわけだ!
昨日いろいろ書籍をググっていましたが、多分Effective Javaあたりから読むとよいのかなと。またはJavaによる関数型プログラミングかな。
他の言語も同様ではあるのですが、入門書はたくさんあるのですが、例えばif文を極力使わないでプログラミングしようとか、Exceptionをどのようなケースで使うのが良いのかとか、ファクトリーメソッドでどのタイミングでインスタンス生成すると良いのかとか、疑問は尽きません.
今からjavaを勉強しても勉強したことを生かしてプログラミングすることももう無さそうなんだけど。
2024年02月19日 プログラミング雑談
デザインパターンを勉強せずになんとなく使っているので説明できない
C++とかJavaとかで継承を学ぶと使いたくなるのがFactory Method。
その時はわかったような気分になるのですが、時々こんがらがってくるのでメモ。
「乗り物」を作る「工場」がある
「乗り物」は「自転車」もあれば「三輪車」もある。
「自転車」を作る「自転車工場」や「三輪車」を作る「三輪車工場」がある。
「乗り物」がProduct、「自転車」や「三輪車」がConcreteProduct
「工場」がCreator、「自転車工場」や「三輪車工場」がConcreteCreator
で、ここから先の正しい定義がいまだによくわからないのです。動的に、その時作りたい乗り物をswitch文などで切り分ける処理は何と呼べばいいのでしょう?
GoFの実装例ではCreatorクラスのCreator::Create()でMINEとかYOURESとかに応じて適切なProductをnewしているようです。
やっぱりちゃんとGoFのデザインパターンをちゃんと勉強しなきゃだな。もしかしてFactory Methodは適切なProductをnewするところまでで、どのように「乗り物」を作るかはAbstruct Factoryとかなのかしら。デザインパターンはつまみ食い状態だから全体像がつかめていない・・・
2024年02月23日 プログラミング雑談
Java AutoValueの私的なメモ
Effective Javaで今更ながらJavaを勉強中
最初の方の章でdataクラスを作るならequalとかちゃんとやらなきゃだめだよとか書いてあるみたい。自分で定義した値クラスを比較してないなら問題ないんでしょ? と思いながら、ちょっとお試し。
githubのAutoValue
detailed documentationをまるっとコピーしてしまうと、コード側の使い方はこんな感じらしい。@AutoValueというアノテーションを書くこととabstractクラスにすることがポイントらしい。インスタンス生成するためにabstractじゃないクラス名が必要だからcreateメソッドも必要ってことかな。
import com.google.auto.value.AutoValue;
@AutoValue
abstract class Animal {
static Animal create(String name, int numberOfLegs) {
return new AutoValue_Animal(name, numberOfLegs);
}
abstract String name();
abstract int numberOfLegs();
}
mavenの場合pom.xmlには次のように書くみたい。${auto-value.version}は適切なバージョンに置き換える。
<dependencies>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<version>${auto-value.version}</version>
</dependency>
</dependencies>
これだけだとAutoValue_Animalなんてクラス知らないって言われるので次の記載も必要みたい
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>${auto-value.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
これでビルドするとtarget/generated-sourcesの下にAutoValue_Animal.javaが作られる。
私はたいしてjavaのコードを書いていないからこれまでこういうことを知らなくても実害はなかったけれど、コンテナに自作クラス(のインスタンス)を入れて何かさせる場合はequalとかちゃんと作らなきゃならないようなので、今は実害が無くてもちゃんと作る習慣を今からつけていかないと将来発見が難しいエラーを作りこんでしまうって事だろうな。
2024年02月24日 プログラミング雑談
匍匐前進
今年作っていたjavaのプログラム、VSCodeでMavenを使っていましたが、gradleも使ってみたくて。
VSCodeなのでGradle for Javaのプラグインを入れて、コマンドパレットで"Create a Gradle Java Project"でKotlinでJUnit5だったかな、そんな感じで選んでプロジェクトを作成。
もう一歩進むたびにやり方をググって・・・
依存パッケージの設定はbuild.gradle.ktsに
dependencies {
// This dependency is used by the application.
implementation("org.jsoup:jsoup:1.17.2")
implementation("org.apache.logging.log4j:log4j-api:2.22.0")
implementation("org.apache.logging.log4j:log4j-core:2.22.0")
}
とか書いて、VSCodeの左の象のアイコン→Tasks→build→buildしたらエラー。
どうやらbuild.gradleを更新したらUpdateする必要があるみたい。Mavenの時はpom.xmlを更新すると更新しますかみたいなメッセージボックスか何かが出てUpdateされていたみたいですが、まだ私の環境はbuild.gradleを更新しますかみたいなメッセージボックスか何かが出ているのですが反映されていないみたい。(追記)JDKとJREをインストールしなおしたら解決しました
とりあえずVSCodeを終了して立ち上げなおせば反映される。
Javaのソースファイルとテスト用データファイルを一式コピーしてbuild。今度はコンパイルが通ったけれど今度はテストでエラー。Webページのhtmlファイルを作るプログラムなので、生成したファイルの中の文字をチェックするのだけれど、UTF-8の文字列にもかかわらずShift-jisのつもりで比較している模様。UTF-8のソースファイルなのにShift-JISとしてコンパイルされているみたい。文字コードが誤認識されていてもビルドが通るとは恐るべし
VSCodeのエクステンションの設定かしらと思ってEncodeとか頑張って探すけれど設定する箇所が見つからない。
いろいろググってたらbuild.gradleで設定するらしい。このサイトの記載をそのまま使わせていただきました。
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
}
すっかり忘れていたけれど、Mavenの時はpom.xmlに
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
みたいなのを書いた気がします。
VSCodeのjavaのプラグイン(?)でCreate Java Project→Maven→archetype-quickstart-jdk8とかで入ってくるcheckstyleとかjacocoとかはまだどうやったら使えるのかわからないし、log4jもまだlog4j2.xmlにパスが通っていないみたいでログが出てこないし、しばらくは前途多難な匍匐前進なのだな
でもググれば何かわかるというのは実に助かります。良い時代ですね。
2024年03月02日 プログラミング雑談
javaでifを使わずにnullじゃなかったら実行する
javaでもC++でも良いのですけれど、コードを書いているとnullチェックのif文が並んで、なんだかなぁ、と思うことが多いです。
例えばjavaで次のような感じ。クラスAaa、Bbbなどは省略します。
public class App {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
create(args[i]);
}
}
private static void create(String devName) {
Map<String, Supplier<Xxx>> factory = new HashMap<>();
factory.put("A", Aaa::new);
factory.put("B", Bbb::new);
Supplier<Xxx> sup = factory.get(devName);
if (sup != null) { // ★
Xxx xxx = sup.get();
System.out.println(xxx.getProduct());
}
}
}
factory.get()のところをgetOrDefault()使ってnullが返らないようにする手もありますが、このケースでは本来エラーになるケースでsup.get()で無駄なインスタンスを生成してしまうのでいやだなぁと。
もう20世紀じゃない。javaでNullじゃなければ実行する、みたいなスマートな方法があるはず。どう調べればよいかわからないのでたどり着くのに時間がかかりましたが、こんな方法があるようです
private static void create(String devName) {
Map<String, Supplier<Xxx>> factory = new HashMap<>();
factory.put("A", Aaa::new);
factory.put("B", Bbb::new);
Optional<Supplier<Xxx>> optxxx = Optional.ofNullable(factory.get(devName));
optxxx.ifPresent(sup -> System.out.println(sup.get().getProduct())); // supにoptxxxが入る
}
java.util.Optionalを使ってofNullableで「この変数、nullかもしれない」と申告しておいて、ifPresentで「もしnullじゃなかったらヨロシク」ってことらしい。
このコードではifPresentで実行までしていますが、生成したインスタンスを返して戻り先で実行させるならこんな感じ。「nullかもしれない」値をOptionalに入れて処理して、最後にorElseでインスタンスを取り出すみたい。
Optional<Supplier<GenHtml>> maker = Optional.ofNullable(factory.get(htmlMode.toLowerCase(Locale.getDefault())));
Optional<GenHtml> makerMethod = maker.map(zz -> zz.get());
return makerMethod.orElse(null);
最初の方の例はこのページに書くためにでっち上げたコードだったけれど、こっちは自分のコードからコピペ。
多分読み慣れればifでnullチェックするよりも読みやすくなるのでしょうね。
問題というほどの問題ではないのですが、ifPresentやmapの中でラムダ式を使うのでjacocoではサイクロマチック数を一つ使ってしまうのですよね。Optionalの処理をメソッドにして追い出してしまうとかいう使い方を想定しているのでしょうかねぇ。
2024年03月10日 プログラミング雑談
どこまでも文字コードが付きまとう
javaでgradle使ってプログラム作るの第2弾。poiでexcelファイルを作る。
cell.setCellValue("日本語文字列");
ってやったら文字化けした。
poi側で何か文字コード設定があるのかと思ってググるのだけれどあまりヒットしない。日本語フォントを設定すれば文字化けが直るとか書いてあるサイトもあったけれどフォントを指定しても直らない。
しばらく悩んで
System.out.println("日本語文字列");
したらこっちも文字化けした(笑)
そうだった、build.gradle.ktsに
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
}
って書いてUTF-8でビルドしなきゃならないんだった
引き続き、
Excelのxlsxファイルを読み込んで条件付きで文字色を変更して別ファイルに保存させるプログラムを書こうと四苦八苦。OPCPackageってなんだかわからないけれどpoiのサイトのサンプルのコピペで
OPCPackage pkg = OPCPackage.open(new File("indata.xlsx"));
って書いてファイルを読むと読み出ししたいだけなのにファイルが何か更新されてしまうみたい。結局
XSSFWorkbook wb_r = (XSSFWorkbook) WorkbookFactory.create(new File("indata.xlsx"), null, true);
って書いて解決。create()の3番目の引数がread onlyにするフラグらしい。
でもなんか別ファイルを作って保存ってpoiではセル一つ一つを別ファイルにコピーする必要があるみたいで面倒らしい。poiの新しめのバージョンではメソッド一つでシートごとコピーできたりしないのかな・・・。後で調べてみる。
2024年03月20日 プログラミング雑談
ChromeBookってLinuxマシンだったんだな
AndroidでもiPadでもいいから電子書籍リーダーや動画プレイヤーとして使えるタブレット端末がほしいと思って購入したキーボード分離型のChromeBook。
購入前の下調べで開発者モードにするとLinuxが使えるとかVisual Studio Codeすら使えるとか知りましたが、Androidアプリが使えればそれで十分かなと思っていました。
ところが、物理キーボードが意外と打ちやすいし、かなキー入力が普通にできる事がわかって、これは携帯用のテキスト入力マシンとして使える! 私の予備のWebページ更新用端末にしたいという誘惑に囚われてしまいました。
ChromeBook購入とは関係なく、これまでC++(クラスと継承が使えるC言語のレベル)で作って使っていたhtml生成用のコマンドラインアプリをjavaで書き換えましたので、これをAndroidアプリにすれば・・・と考えて、PCにAndroid Studioを入れてjavaのコマンドラインアプリにAndroid用のUIでくるむことを検討してみました。多分一週間くらいちゃんと勉強すれば作れそうな気がしました。
でも今はちょっとAndroidアプリ作成の勉強をする時間が確保できない(今はjavaで自分で納得できるレベルのアプリが書けるようになりたいということで勉強中なので)ので、ChromeBookの開発者モードにjreを入れて、現時点のjavaアプリをそのまま使っちゃえばいいじゃんという発想に至りました。
前置きが長くなりましたが
- ChromeBookの「設定」→「詳細設定」→「Linux開発環境」
で数分でLinuxの環境ができてしまいました。
前提知識を持っていなかったので、開発者モードってChromeBookの普通の環境を動かしている土台のLinuxを公開するモードなのかなと思っていましたがもしかしてChromeBookのOSの上で動く仮想OSとかコンテナなのかも。このあたりはおいおいググって調べてみようと思います。
Linuxのシェルが開きましたので、最初はlsコマンドなどが動くことを確認。ChromeBookのメニューに「vim」とか出てきたので起動してみると本当にvimっぽい。
java --version
と打ってみましたがjavaなんて知らないって言われてしまいました。
ググってみましたら
sudo apt-get install default-jre
でjreが入るようです。
$ java --version
openjdk 17.0.10 2024-01-16
OpenJDK Runtime Environment (build 17.0.10+7-Debian-1deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.10+7-Debian-1deb12u1, mixed mode, sharing)
PCで動かしているhtml生成のコマンドラインアプリを持ってきて動かしてみましたら、無事動きました。
2024年03月29日 ChromeBook CZ1000DV
エレコムの安いキーボード(5年経過)の潤滑化メンテ
職場であてがわれたパソコンのキーボードが"X"の下にaltキーがあって"Z"の下にWindowsキーがある極悪なキー配置だったので苦情を言って変えてもらったのだけれど、それもなんかイマイチだったのでBYOD。
別にRealforceやメカニカルのキーボードにしてほしいと言っているわけではなくて、結局使っているのはエレコムの安いキーボードであるところのTK-FCM103XBK。今Amazonで見たら830円だった。安い。
さすがに5年も使っていると打鍵感にひっかかりが出てきて、しばらくキーボード欲しい病を発病していました。
自宅ではFILCOのメカニカル。茶軸の打鍵感が心地よくて15年位前だったかにヨドバシの店頭で一目惚れして購入。その後、今から5年前に今使っている茶軸のコンパクトタイプのキーボードに変えました。Realforceも何度も検討したのですが、どうも打鍵感にワクワクを感じなくて。店頭で触った感じはキーに引っ掛かりも感じず滑らかでいいのですが、なんだろう、メカニカルのCherryの茶軸と比べて押し始めのラバーカップ感とでも言えばいいのか、モニョっとした感じが、何万円も出して買うキーボードではない感じがしてしまっています。
ラバーカップの打鍵感も千円前後のキーボードならば許容範囲。でも冒頭に書いたように5年も使っていると打鍵感に引っ掛かりが出てきて、滑らかな打鍵感に憧れてRealforceやメカニカルのキーボードを家電量販店の店頭で感触を確かめながら、2万円とか3万円とかの値札を見て購入をためらっていました。キーボードは商売道具でもあるのでケチりたくはないのですけれど、値段分の価値を感じられなくて。
ってことで(前振りが長い)、結局またエレコムの安いのを買ってしまいました。TK-FDM105TXBK。ワイヤレスで1,280円だったので。うん。打鍵感に引っ掛かりもなく良い感じ。これで十分。
私のキーボードの嗜好は、必須の条件はシリンドリカルのキートップで左altキーが標準的な位置にあることだけかもしれません。テンキーがあるとマウスが遠くなるのでテンキーレスとかコンパクトタイプのものを最近は選択してしまっています。あったらいいな、くらいの条件が、打鍵感やなんちゃってでいいのでステップスカルプチャ。最近はHomeキーやEndキーもよく使うのであまり特殊なキー配置は敬遠してしまいます。
で、今まで使っていた打鍵感に引っ掛かりが出てきたキーボード、ググったところルブと呼ばれているらしい、グリス類で打鍵感を改善することにトライ。
ググって見かけたのがメカニカルキーボードのキースイッチを分解してグリスを塗ったり、メンブレンキーボードの可動部にシリコンスプレーする方法。私は電気接点があるメカニカルキーボードに絶縁性の何かを塗るとか怖くてできません。シリコンスプレーはメカニカルキーボードを使い始める前にメンブレンのキーボードで試したことがあります。その時の記憶は、打鍵感の引っ掛かりは解消するのですが動きに液体っぽい抵抗感が感じられてイマイチというもの。
今回は何年か前に鍵穴の潤滑用にフッ素樹脂スプレーを入手していますので、フッ素樹脂スプレーで打鍵感の潤滑化に挑戦。鍵穴があんなに滑らかになるのだもの。きっとキーボードにも効果があるに違いありません。シリコンスプレーよりずっと高価でしたが、スプレー後すぐに乾いてサラサラ感があるのでシリコンスプレーと違って液体っぽい抵抗感も無いに違いない。
ところがTK-FCM103XBKってキーキャップを引っ張ってもキーが抜けない。Y字型の特殊なネジが使われていて分解もままなりません。830円で買えるキーボードの打鍵感改善のために900円超のフッ素スプレーと500円弱のY字ドライバーか・・・と思わないでもありませんが、今回新規購入したのはY字ドライバーだけなので気にしない。これでもホームセンターを3件まわってやっと見つけた安価なY字ドライバーだったりします。地元のホームセンター、コメリで購入。ホームセンタームサシには確か千円超だったけれどもっと太いタイプのY字ドライバーがあったような気がします。どうも話がすぐにわき道にそれますが・・・。
キーボードの裏ブタのネジを外します。このキーボード、ラベルのシールの下にネジが隠されていないあたり構造が良心的。ACアダプターとかいくつか分解したことがありますがラベルのシールの下にネジが隠れているのがデフォルトだったので、少し覚悟をしていたのですが、ラベルをはがさなくてよくてちょっとうれしい。
裏ブタを外すとキーの部分とメンブレンのシートと裏ブタに分かれます。キーの部分はひっくり返してもキートップが外れない構造。新聞紙を広げてキーの部分をひっくり返して置き、可動部にフッ素樹脂スプレーを吹きかけました。しっとりした感じになり、気化熱でキーボードがひんやり。可動部にスプレー液がちゃんとつくようにキーをカチャカチャ動かして、乾燥するのを待ちます。少し白っぽくなるのはこのスプレーの特性。どうせ見えなくなる部分なので気にしない。
有機化合物っぽい異臭が室内にこもるので外は暴風雨の夜でしたがやむなく窓を開けて換気します。
キーボードを組み立てて打鍵感を確認。引っ掛かりが解消。液体っぽい抵抗感はなく、ラバーカップの特性がダイレクトに感じられる打鍵感。キーを押したときのモニョっとした感じがRealforceっぽい。830円のキーボードでこの打鍵感ならお値段以上の価値がありますよ、これ。
でもやっぱり私はメカニカルの柔らかいバネっぽい押し下げ感の方が好きだわ。
そういえばせっかくねじを外したんだから標準的な+ネジに付け替えれば良かった。どうせM3くらいの安いので大丈夫だろうし。
フッ素樹脂スプレーは呉のドライファストルブ、Y字型のドライバーはSUNFLAGのNo.17-Cでいけました。No.17-Cはネジに合わせてみるとちょっと細い感じなので、3mmくらいのサイズのがあると良いと思いました。
2024年03月30日 エレコム廉価版キーボード TK-FDM105
エレコムの安いキーボードの潤滑化メンテ手順
キーボードをいわゆる「ルブ」したいと思いながらしばらく踏み切れなかったので、同じように踏み切れない人の背中を押すつもりで、エレコムの安いキーボードTK-FDM105TXBKの潤滑化について書きます
用意するもの
- 潤滑化対象のキーボード
- Y字型ドライバー
- 潤滑用のスプレー
Y字型のドライバーはSUNFLAGのNo.17-Cが近所で安かったのでこれを使いました。
ネジの溝部分のサイズが2.2mm向けのドライバーのようです。これでもエレコムのキーボードのネジは回せましたが、もっと大きなドライバーが好ましいと思います。多分3.0mmくらいあった方が良いと思います。
潤滑用のスプレーは呉のドライファストルブを使いました。
分解
ネジの場所は赤く丸をつけたところです。水抜きの穴もあるのですべての穴にネジが入っているわけではありません。
ちゃんと力を入れてドライバーを押し込む感じでネジを回す必要がありました。サイズが合ったドライバーならそれほど気を使わなくても良いと思います。
裏ブタと表のキーボード側の分離はキーボード側に3箇所小さな爪がありますので、爪の場所は裏ブタ側を外に押し広げる感じで外すと良いでしょう。
ネジはこんな感じ
Y字のネジを一般的な+ネジに付け替えたくて近所のホームセンターに行きましたが同じサイズのネジは置いていませんでした。タッピングネジで鍋タイプの3x8よりは1mm位短くて、3x8の先端1mm位を切り落とした感じに見えます。
(追記: B0型タッピング ナベ M3×7 になるみたい)
中の構造
キーボード部分を外した裏ブタ側はこんな感じ。
メンブレンの白いシートは有線タイプのTK-FDM103と同じものだと思います。メンブレンのシートと右上の基板は3つのネジで圧着させる構造。この基板を有線タイプ、無線タイプ、Bluetoothタイプで使い分けるのでしょう。ちょっと高価なBluetoothタイプでメンブレンのシートが接触不良を起こしたら安い有線タイプを買ってきてシートだけ入れ替えれば使えるのではないかな。購入時期が何年も違うと中身が微妙にバージョンアップして互換性が失われているかもしれませんので積極的におすすめはしませんが。そうでなくても5年使った私のキーボードは、今回買い足して気が付きましたが、キートップがツルツルになっていたり左手親指の腹があたるキーボード下部がすり減っていたりしましたので、数年使ったのならば修理とか考えずに買い替えた方が良さそうです。2万円超のRealforceだと10年位使いたいかも?
キーボードの裏側、キートップの取り付け部分
キートップは筐体に爪ではまっている構造です。キートップを引っ張っても抜けないように作られているのですね。
キーを押し込むとこんな感じ
スプレー作業
キーを押し込むとキートップと筐体の接触部分が露出しますので、ここにドライファブのスプレー液を付着させる感じで作業しました。作業時はキーを押し込まなくても筐体をひっくり返して広げた新聞紙の上に置けば自然とキーが押された状態になります。スプレー付属のストローを溝のように見える隙間に差し込んで、スプレー液で濡れようにします。
気にしなくても良いのかもしれませんが、液がちゃんとキートップと筐体の接触部分にまんべんなく付着するように、キー4つくらいずつまとめてスプレーして、乾く前に手でキーをカチャカチャ押し込んでました。キートップが気化熱でひんやりすると、キートップにも液がちゃんとついてるんだなと安心できる感じ。
どのくらいの量をスプレーするのが最適かわかりませんが、キーボードの引っ掛かり感が解消していれば目的は達成できているのでヨシとしています。
天候などの関係で可能ならば屋外、せめて窓を開け放った室内で作業することをお勧めしておきます。有害物質は使われていないと思いますが、ちょっと溶剤っぽいにおいが気になるので。
組み立て
スプレー液がちゃんと乾くのを待って、キーボードを組み立てます。
呉のドライファストルブは乾くと白くなります。ところどころ白い汚れが付着したかなって感じになります。まあ組み立ててしまえば見えないところですので気にしません。
あ、白くなった写真を撮り忘れました・・・。
効果
PCに接続して試し打ち。
気のせいかもしれませんが打鍵音のカチャカチャの高音部が少し静かになった気がします。
押下感は滑らか。わざと斜めに押し込もうとしてもキーの引っ掛かり感はありません。(昔、斜めに押し込んでも引っ掛かりが無いパンタグラフタイプのキーボードが好きだった時期がありました)。メンブレンのラバーカップの変形する感触なのだと思いますが、押し始めがクニュっとして一番重い感じ。このクニュっとした感触がいまいち好きになれなくて、メカニカルのキーボードの方が好みなんだと思います。とはいえ職場で支給されたキー配置レベルでダメダメなキーボードに比べれば、このキーボードは十分ハッピーです。
あと、これも気のせいかもしれませんが、スプレー前よりもキーが重くなった?
今回は1週間くらい使ったくらいのほぼ新品に潤滑スプレー処理をしましたので劇的な改善はありませんが、斜めに押し込もうとしても引っ掛かり感はありませんので私の変な打鍵癖でキーが引っかかって入力されない(特にshiftキー)は改善されると思いますし、これだけ滑らかな打鍵感ならば高価なrealforceは私にはいらないと思いました。キーボード欲しい病がほぼ治りました。少なくともrealforceは欲しいものリストから削除されました。(茶軸のメカニカルはまだちょっと魅力的なのですけれどね)
2024年04月06日 エレコム廉価版キーボード TK-FDM105
Android StudioをJavaで使うときライブラリのjarはどこに置くの?
私のWebページのスタティックhtmlファイルを生成するjavaプログラムをAndroidアプリ化しようとトライ中。
ググっていると広告ばっかりでイライラしてくるので入門書を購入。
あら、でもAndroid Studioでjavaのライブラリjarをどうやったら使えるか書いていない本を買ってきてしまったみたい。
(1) プロジェクトのviewでappフォルダ右クリック → New → Directory でlibsフォルダを作成
(2) エクスプローラーアプリからjarファイルをドラッグしてきてAndroid Studioのプロジェクトのviewの今作ったばかりのlibsフォルダにドロップ
(3) Copyするファイル名とフォルダを確認するダイアログが出るのでOKで閉じる
(4) プロジェクトのviewでCopyしたjarファイルを右クリック → Add as Library → Addするモジュールの確認ダイアログがでるのでドロップダウンリストから選択。デフォルトで良いみたい。
するとbuild.gradle.ktsに「implementation(files("libs\\jsoup-1.17.2.jar"))」みたいな行が追加されて、ライブラリが使えるようになりました。
jsoupはこれで使えたけれど、log4j2が実行時にエラーになる。まだAndroid Studioの使い方が全然わかっていないのでどんなエラーか把握できていないしどうやってデバッグすればいいかも勉強中。そもそもlog4jの使い方もわかっていないのでlog4jの使い方をちゃんと読めばいいのかな。
2024年04月07日 プログラミング雑談
実行可能jarを作る
javaのCLIでの実行jarの作り方を覚えてられないのでメモ
マニフェストファイルを作ります。
Manifest-Version: 1.0
Class-Path: .
Main-Class: com.my.App
classフォルダで
jar cvf [作りたいjarファイル名] [classファイルが入っているフォルダ名。例えばcom]
jar uvfm [作ったjarファイル名] [マニフェストファイル名]
2024年04月08日 プログラミング雑談
OpenJDKでJavaFXを使う
新しいバージョンのJavaが使えると限らないけれど、Java 8くらいならばどこでも使えそうな気がするので私が書いているJavaプログラムはターゲットをJava 8にしています。
OracleのJREはJava 8でもバージョンに気を付ければ使えるけれど、JDKはOracleのアカウント登録が必要で使いにくいのでOpenJDKを使っています。
今回買ってきたJavaの本はGUIアプリでJavaFXを使っているので本のチュートリアルに書いてあるHello World!をポチポチ入力。でもjavafx.application.Applicationがimportできない。この本はOracleのJDKをインストールしている前提なので、JavaFXなんて使えて当たり前でしょ? みたいなノリで全く説明なし。
いろいろググった結果、JavaFXを使うならばAmazon CorrettoにはJavaFXが入っているので簡単なようです。
adoptiumのOpenJDKをアンインストールしてCorrettoを入れてみました。とりあえずチュートリアルのJavaFXのHello World!はあっさりコンパイルできて動きました。
JavaのUI、Swingならばたいていどこでも使えるだろうと思ってちょっとHello Worldを動かしたことがありますが、Windowsのディスプレイの拡大/縮小はプログラマが意識してコードを書く必要がありそうで、私の200%拡大設定ではUIが小さくてなんだかなぁと思っていました。JavaFXはディスプレイの拡大/縮小の設定が効いているように見えますし、ファイル選択のコモンダイアログもWindowsのを使えているみたいなので良いかも。
ChromeBookでもJavaFXは使えるかな?
jarを作ってChromeBookに持って行ったけれど動かない。javaFxが入っていないのかな。
sudo apt-get insatll openjfx
しても"Package 'openjfx' has no installation candidate"って言われてインストールできませんでした。
2024年04月08日 プログラミング雑談
Androidアプリでlog4j2が使えない
自作javaアプリをAndroidアプリに作り替えようとしているのですけれど、使っているライブラリ、jsoupとlog4j2のうちjsoupはAndroidでも使えそうなのですけれどlog4j2の方はビルドすらできませんでした。
ちゃんとエラーメッセージを見たらlog4j2のパッケージのjarにMETA-INF/DEPENDENCIESというファイルがあるのがダメらしい。このファイルをjarから削除したらビルドだけは通るようになりました。
でも、Androidアプリで使おうとするとエラーになってダメなのは変わらないのですけれどね。ファイルに書き込もうとするときに何か制限があるのかしら。Androidアプリに関しては初心者未満だから手も足も出ない感じ。
2024年04月10日 プログラミング雑談
原稿ファイルにinclude機能を追加してました
毎回同じことを言っていますが、このwebページはテキストファイルからスタティックのhtmlファイルにプログラムで変換しています。
だいたい一つのテキストファイルが一つのhtmlファイルに相当しますので、indexページ(トップページ)と過去ログページと話題ごとのまとめページ、例えばプログラミング雑談に同じ文章をコピペしていました。これが地味にめんどくさかったので原稿のテキストファイルに別ファイルをincludeできるように機能追加してました。
原稿テキストファイルにincludeするファイル名を書いておいて、includeファイルが見つかったら挿入するだけの話なんですけれど、includeするファイルは原稿テキストファイルの相対パスにしておかないとユーザーの使い勝手が悪いし、このプログラムは将来Androidにもっていきたいので絶対パスはどうも使わない方が良いらしい。ってことで
Path currentFile = Paths.get(原稿ファイル名);
Path includeFile = Paths.get(includeファイル名);
String includeFileString = currentFile.resolveSibling(includeFile).toString();
でincludeファイル名を処理してから読み込んでいます。
html生成プログラム実行時のカレントフォルダは原稿ファイルと別フォルダですけれど、原稿ファイルとincludeファイルは同じフォルダという条件では今のところこのコードで動いています。原稿ファイルとincludeファイルが違うフォルダのケースはまだテストしていないので、テストしなきゃなぁ・・・
2024年04月20日 プログラミング雑談