20200522のJavaに関する記事は16件です。

初心者の単語No4(Javaコマンド、JVM)

フィールド
・クラスで宣言した変数名
・レコードを抗セする単位。
(その他の意味 分野・領域など)

javaコマンド

Javaアプリを起動するコマンド。
(Javaプログラムを実行する)

コマンドのオプション

オプション 概要
-classpath 関連するclassファイルの検索先
--module-path モジュールの検索先
-jar jarファイルを実行
-version Javaバージョンを表示

例:Test.jarを実行する例。パラメーターとして「太郎」を設定。

> java -jar Test.jar "太郎"

※その他コマンド系は、またそのうち纏めて記述します。

JVM(Java Vitual Machine)

Javaのプログラムを動かすためのソフトウエア。
その他の言い方として、「Java仮想マシン」「JavaVM」

Javaは、どのマシンでもJavaが動作することを思想として作られた言語。

JVMの仕組み

①Javaプログラム⇒②JVM⇒③OS
①を解釈し、③のOSで実行可能な形式のコードに変換して動作させる。
②のJVMはJavaで作ったプログラムをプラットフォームに依存しないで動かすために必須ということ。

①から②の際にテキストコードをバイナリコード(マシン語)に変換
②から③の際にバイナリコードを読み込んでネイティブコードに変換

JVMの構成

大まかに3つに分けた領域が存在する。
1.New領域
2.Old領域
3.Permanent領域
がある。
1から2の領域ではヒープ。
3の領域では非ヒープ領域。

ヒープ

OSやアプリケーションなどのシステムが利用するメモリ領域のこと。
※JVMのヒープ領域はオプションで自由に設定を変更可能。

1.New領域
⇒更に3つの領域に分類される。
⇒オブジェクトがインスタンス化された際にEden領域に配置
⇒Edenのメモリがいっぱいになると、オブジェクト退避のためにFrom領域とTo領域に格納。
2.Old領域
⇒New領域に格納されているオブジェクトで使用期間が長い情報が管理されている。
⇒OldがいっぱいになるとFullGCと呼ばれる処理が頻繁に起こる。
※FullGCは重い処理の為実行されている間はシステムが止まる。
3.Permanent領域
⇒クラスやメソッドなどの情報が格納。
【補足】
GCはガーベージコレクションの略。
⇒メモリ領域中の使用済みのメモリ領域を整理し、空き領域を作ること

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのdouble型

double型

double型は小数点以下を持つ数になります。
int型は整数で、1とか3とかです。
対してdouble型は1.2とか3.5とかの少数点以下に定義します。

小数同士の計算

【例】

Main.java
class Main {
  public static void main(String[] args) {
    double number1 = 8.9;
    double number2 = 1.2;
    System.out.println(number1 + number2);
    System.out.println(number1 - number2);

  }
}

上記の例だと結果は11.1と7.7になります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

7日でJAVAを習得する方法

今日はTwitterであるものを見つけました


未経験からフリーランスエンジニアを目指すなら
最低1年は勉強しないとダメですよね?
いいえ、違います!
プログラミング習得は
7日あれば誰でも可能です

よくあるプログラミングスクールの売り文句ですね

7日で本当にプログラミングを習得できるのか、僕がやってきたJavaの勉強方法を元に検証してみようと思います。

前提

if文、for文くらいは学校で聞いたことあるけどいまいち覚えておらず、オブジェクト指向プログラミング(OOP)は知らないものとします
メンターのような人はおらず、すべて一人で勉強するものとします
インターネットを使え、必要な本は事前に入手しているものとします(ただし、Twitterで人に聞く、などはできないものとします)
Javaを勉強する7日間は仕事や用事などはないものとします
自分用のメモは取らないものとします(メモを取る時間のほうが長くなってしまうため)

検証

では早速はじめていこうと思います
僕が最初に取り掛かったもの、それは…

Progate

インターネットでちょっと調べると真っ先に出てきますね!
途中まで無料で受講できる上に、Javaの実行環境が用意されている状態でスタートできるためかなりのスピードでこなすことができます
今回は月額費用約1000円を払い、有料のコースも受講します
Progateはこちらから

先に言っておきますが、ステマ的なものではないですw
最も早く勉強を進める方法として、初期段階ではProgateはかなり有効だと思っています

JavaのコースはI~Vまでありますが、8時間もやれば終わるでしょう
途中で道場?みたいなのがありますがそれは無視していきましょう
何せ時間がないですから!

Progateで理解できること
変数、if文、for文などの基本的な構文
クラス、メソッド、インスタンス、カプセル化、継承、ジェネリックスなどのオブジェクト指向プログラミングに関する部分

スラスラわかるJava 第2版

Progateでおおよその部分は最速で流していけますが、Progateでは出てこない部分があります
例外処理、インターフェース、関数型インターフェース、ラムダ式、ストリーム、リフレクションなどなど…
Progateは最速で勉強するための優れたツールだとは思いますが、内容量がめっちゃ少ないです
正直、Progateの内容を完璧に習得したとしても何かが作れるレベルではありません

Progateでは出てこなかった部分をスラスラわかるJava 第2版でささっと勉強してしまいましょう!
スラスラわかるJava 第2版はこちらから

ここで注意をしておくと、スラスラわかるJava 第2版は若干分かりづらい部分があります
何故かというと、Progateでは説明、コーディング、実行という過程があったのですが、スラスラわかるJava 第2版は説明、問題で終わりです
サンプルコードは出てくるのですが、実行結果がイメージしづらく若干分かりづらいです
しかし、この本の説明はかなり丁寧なためしっかり読めば理解できます

スラスラわかるJava 第2版で理解できること
例外処理、インターフェース、関数型インターフェース、ラムダ式、ストリーム、リフレクション、マルチスレッド、アノテーション、コレクションなどなど…

ただし、これら全てをはじめから完璧に覚える必要はありません
例外処理、インターフェース、関数型インターフェース、ラムダ式、ストリームあたりがなんとなく理解できればそれでOKです
何故かというと、この後死ぬほど出てくるのでここで必死になっても…って感じだからです

知っているところは飛ばしてしまって良いです
それであれば大体10時間くらいで読破&理解までいけると思います

Java SE 8 Silver 問題集

俗に言う黒本です
Java SE 8 Silver 問題集はこちらから

今まではなんとなくだった理解が、この本を読むとしっかり脳みそに刻み付けられます
この本は何回か読めば簡単にJava Silverを取ることができるようになります

と、言う意味ではかなり価値があると思うのですが、今回は時間がありません
staticメソッドとインスタンスメソッドの違いが理解できていればここは飛ばしてもう次に行ってしまいましょう(別に資格が目的ではないので!)

Java プログラマ Gold SE 8

俗に言う紫本です
Java プログラマ Gold SE 8はこちらから

資格取得が目的であればJava Goldの黒本も読むべきですが、今回は紫本だけで良いでしょう

Java GoldはSilverでは出てこなかったもう少し詳細な情報が載っています
ここらへんからようやくJavaっぽさが出てきますw

今までは理解したとこで何が作れるの??ってレベルでしたが、流石にJava Goldレベルになるともうちょっとマシになり、ファイルへの読み書き、データベースアクセス、マルチスレッドらへんが実装できるようになります

Java プログラマ Gold SE 8で理解できること
JDKに同梱されているライブラリーの使い方
関数型インターフェース、ラムダ式、ストリームなどなど

この本は結構内容も重いので、48時間くらい取りましょうか

デザインパターン(TECHSCORE)

次の本は…と言いたいところですが、ちょっと一休み、GoFのデザインパターンを学びましょう
デザインパターンに関する本はいろいろあるのですが、どれも実装例を書いてあるだけであまり意義を感じなかったので無料で見れるWebサイトで済ましてしまいましょう

TECHSCOREがかなりわかりやすく解説してくれてます
デザインパターン(TECHSCORE)はこちらから

ここで重要なのは、実装方法に囚われないことです
今理解したいのは実装方法ではなくデザインパターンです

ここは3時間くらいでささっと終わらせちゃってください

Effective Java 第3版

この本はJavaの生みの親であるJoshua Blochさんの著書を翻訳したものです
初版から3版まで出ていますが、それぞれで内容が違います
3版ではJava SE 8の内容も記載してくれているため、まさにそのまま使える手法が載っています

この本を読む前提として、Javaの基本とデザインパターンがなんとなくでもわかってないといけません
逆に言えば、この本を読んで意味がわかるレベルであればもはや初心者は抜け出したと思っても良いでしょう
Effective Java 第3版はこちらから

Effective Java 第3版で理解できること
Javaの設計、実装で気を付けなければならない点
不変オブジェクトの有用性

この本でびっくりするのは、Java Goldで一生懸命勉強した内容が「そんなもん使うな」と一蹴されているところですw
コーディング規約とかもこの本を元に作られてるのかな?っていうのをよく見かけるので、これが理解できればなんとなくの設計、実装はできちゃいます

この本もかなり重いので、60時間くらいとっておきますか

Spring Boot 2 プログラミング入門

さて、Javaという言語についてはここまでである程度理解できたと思います
ここからは、実際に仕事で使う領域を触っていきましょう(ごめんなさい、ここまでのは理解してても仕事になるかは微妙なんです…)

Javaのフレームワークと言えばSpring Framework!!!
その新顔でSpring Bootというのがいます
めっちゃかんたんにいうと、Javaを使ってWebサーバーが作れるようになります
Spring Boot 2 プログラミング入門はこちらから

この本はかなり丁寧に解説してくれており、インターネットで適当なWebサイトを見るよりはるかに質が良いです
ただし、中身がちょっと古いんですよね…

環境構築はSTSを~みたいなこと言っているんですが、今はSpring initializrを使ってしまえば一発で環境構築終わりますw

いやー、めっちゃ便利ですよね
僕はこの本読み始めてからSpring initializrの存在を知ったので読み始めでめっちゃ躓いた思い出がありますw

この本では最初のほうでGroovyという言語を用いてコードを書いているのですが、ここまで来た人であれば勘でJavaに直せます
ちなみに、ビルダーはMavenを使ったパターン、Gradleを使ったパターンで解説がされているのですが、絶対にGradleを使ってください

今はインターネットでいろいろ調べるとしっかりMavenでのパターンの解説もされているのですが、Spring Frameworkとそれに付随するライブラリー各種は脱XMLを目指しています
MavenだとXMLで書かないといけないのですが、GradleはJavaっぽい感じで書けます
Javaっぽいというか、実際にはGroobyなんですけどね

Spring Boot 2 プログラミング入門で理解できること
MVCの基本
環境構築
Thymeleaf(テンプレートエンジン)の使い方
データベースアクセス

この本はWebサービスを作る、というのがひとつの目標になっているため、Thymeleafを使った画面周りの解説が結構多いです
SpringよりもThymeleafの解説のほうが多いような気がするくらい多いですw

言い忘れていたのですが、データベースアクセスはMybatisを使ってしまうのでデータベースアクセス部分は飛ばしてしまって結構です
その代わり、Mybatisのドキュメントを読んでおいてください
Mybatisの公式ドキュメントはこちらから
Mybatis-Springの公式ドキュメントはこちらから

Mybatisのドキュメントってなぜかバラバラになってるんですよね…w
Mybatisをちょっと検索してみると、日本語化が不安、みたいなことが書いてあったりするんですが、全くそんなことないです
かなりわかりやすく、無駄な部分が少ないためちょっと空いた時間でスラスラ読めてしまいます

Mybatisの他にもHibernateというのも人気らしいのでそっちも勉強しといたほうが良いかもですね

Spring Boot 2 プログラミング入門とMybatisの公式ドキュメントを合わせて15時間くらいとしましょうか
Spring Boot 2 プログラミング入門は分厚いですがすっ飛ばせる場所が多くて良いですね

Spring 徹底入門

とうとうこれで最後です
これが読めれば、かなりイケイケな感じ?になれると思います

ちょっと古いのですが、Springの重要な部分が網羅されています
説明もかなり丁寧でわかりやすく、Spring Boot 2 プログラミング入門で触れなれなかった部分もしっかり解説されています
Spring 徹底入門はこちらから

ただ動けば良い、ではなく、Springの機能を使っていかに良いシステムを作るか、いかに開発工数を減らすか、みたいな部分が書いてあります

僕もまだこの本読破した訳ではないので知らない部分もあるのですが、ほぼすべてがここに詰まっていると言っても良いレベルだと思いますw

ただ、バージョンアップに伴って追加された書き方や、非推奨となった書き方があったりするのでそこらへんはこの本を読んだ後に追っかけていきましょう
下記の記事が簡潔に説明してくれているので是非見てみてください
令和時代に「Spring入門」「Spring徹底入門」を読むとき気をつけるべきN個のこと

この本はほぼ丸暗記なので、24時間くらいでささっと読破しちゃってください
わからない部分は後で見返せばいいんです

検証結果

7日でJavaを習得することができるのか、結果発表です

まずは必要な時間を計算してみましょう

Progate
8時間

スラスラわかるJava 第2版
10時間

Java プログラマ Gold SE 8
48時間

Effective Java 第3版
60時間

デザインパターン(TECHSCORE)
3時間

Spring Boot 2 プログラミング入門 + Mybatis公式ドキュメント
15時間

Spring 徹底入門
24時間

合計168時間!

7日*24時間は168時間なので…

結論!

7日でJAVAを習得することはできます!!!!

いやー、7日でJAVAを習得することってできたんですね
寝ずに7日集中力が続けばですけど…w

まとめ

プログラミングスクールは嘘つきではない、ということが証明できました
独学はどうしても嫌だ、という人はプログラミングスクールという手もありなんじゃないでしょうか
本だったら全て合わせても3万円あれば足りるくらいなので、メンターに相当価値がないと費用対効果は良いとは言えないですが

でも、あえて7日でプログラミングを習得しようとするなんてなんて無謀なことか…
7日でプログラミングを習得しようとしている人たちは頑張ってください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java(オーバーライド)

オーバーライドを活用する

Hero.java
public class Hero {
  String name = "勇者";
  int hp = 100;
  //逃げる
  public void run() {
    System.out.println(this.name + "は逃げ出した!");
  }
}

SuperHeroクラスにrun()を再定義する

SuperHero.java
public class SuperHero extends Hero{
  boolean flying;
  //撤退する
  public void run() {      //Heroクラスにも定義してあるが、再定義(上書き)できる
    System.out.println(this.name + "撤退した!");
 }
}

HeroとSuperHeroのrun()を呼び出す

Main.java
public class Main {
  public static void main(String[] args) {
    Hero h = new Hero();
    h.run();
    SuperHero sh = new SuperHero();
    sh.run();
  }
}

実行結果
勇者は逃げ出した!
勇者は撤退した!

継承の禁止

Stringクラスと宣言時にfinalがついてるクラスは継承できない

Main.java
public class Main extends String{

Stringクラス禁止は、javaのAPIリファレンスでも確認できる

Main.java
public final class Main {

オーバーライドの禁止

宣言時にfinalが付けられたメソッドは、子クラスでオーバーライドできない

Hero.java
public class Hero {
  String name = "勇者";
  int hp = 100;
  //逃げる
  public final void run() {     //run()はオーバーライドできない
    System.out.println(this.name + "は逃げ出した!");
  }
}

public final void run()先ほどの、SuperHeroクラスのrun()メソッドは無効になる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【弊社新人に向けて】isXXX系メソッドについて

isXXX系メソッドって例えば?

FileクラスのisFileisDirectoryメソッドなどがあります。
Fileクラス公式ドキュメント

特徴は?

シンプルにbooleanを返します。
booleanとはtruefalseといった真偽値を表すデータ型です。
if文の分岐条件やwhile文の継続条件として用いることができます。

isXXX系メソッドのコード例

例としてisBlankメソッドを作成してみます。

isBlank
// 指定された値が空文字かを判定する。
// 空文字であれば true。
// そうでなければ false を返す。
public boolean isBlank(String value) {
  if (value.isEmpty()) {
    return true;
  }

  return false;
}

使い方は?

先程作成したisBlankを例にコードを示します。

まずif文です。

分岐条件として使用する
if (isBlank(value)) {
  // 文字が入力されていない場合の処理
  System.out.println("文字が入力されていません。");
} else {
  // 文字が入力されている場合の処理
  System.out.println("入力された文字は「" + value + "」です。");
}

if(isBlank(value))この様に記述することで、
「値が入力されていなければ」という意図を、読み手に対して明確に伝えることができます。

続いてwhile文です。
!isBlankとすることでtruefalseを反転させています。

継続条件として使用する
while (!isBlank(value)) {
  // 文字が入力されている場合の処理
  System.out.println("入力された文字は「" + value + "」です。");
}

while(!isBlank(value))としています。
if文同様、「値が入力されていれば」という意図が明確です。

value.isEmpty()でいいじゃん

間違いではありません。
しかし、時としてblankの定義は変更されることがあります。
先程のisBlankは、単に空文字であるかどうかのみ判定しています。

もし、引数がnullだったら?
nullに対してメソッド呼び出しを行うと例外が発生してしまいます。

// value の中身が null だと java.lang.NullPointerException が発生
value.isEmpty()

null に対応する

空文字の判定処理をメソッド化しておくことで、null対応も容易に行うことができます。
では、実際にisBlanknullに対応させてみます。

isBlank
// 指定された値が null または空文字かを判定する。
// null または空文字であれば true。
// そうでなければ false を返す。
public boolean isBlank(String value) {
  if(value == null) {
    return true;
  }

  if(value.isEmpty()) {
    return true;
  }

  return false;

  // 以下の様に書くことも出来ますが、新人向けということで。
  // return value == null || value.isEmpty();
}

isBlankに以下のロジックを追加しただけです。

追加された行
  if(value == null) {
    return true;
  }

この様に、1箇所に修正を加えるだけで、isBlankを呼び出している箇所全てに変更を適用することができます。
コードを書き終え、いざテストをしようとした段階でblankにはnullも含まれるよ、なんて言われても問題ありません。

まとめ

他の誰かが、明日の、1週間後の、1年後の自分がそのコードの面倒を見ることになるかもしれません。
こんな感じで処理をまとめてしまえば後々楽になります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Firebase]アプリをアンインストールしてもFirebase AuthのcurrentUserがnullにならない問題

アプリをアンインストールしてもFirebase AuthのgetCurrentUser()の戻り値がnullにならなくて困ったので解決方法をここに記録します。

解決した方法

調べたところ、この問題はandroidの自動バックアップ機能によるものらしいです。
マニフェストからこの機能のオフにしたら解決しました。
具体的には、manifest.xmlに以下のコードを追加しました。

manifest.xml
 <application
  android:allowBackup="false"
  android:fullBackupContent="false"
  ...

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字列リテラルとインスタンス

(新人エンジニアのふぎと君。
今日はJavaのコードをせっせと書いているみたい)

Stringクラスのインスタンス

「…と、ほなそろそろStringクラスで文字列作るか」

String string1 = "Hello";
String string2 = new String("Hello");

「遊び心を加えて書き方変えてみたで」
「これは先輩もくすっと笑ってくれるやろ!」

先輩のもとへ

「先輩、コード書いたんで見てください」
「おもろいですやろ」
「んー、どれどれ・・・?」
「おん?」
「なあふぎと、お前この違いわかってへんのと違うか?」
「・・・?どの違いですか?」
「Stringクラスの初期化の仕方の違いや」
「違いって・・・どっちもStringクラスのインスタンスを
つくってるんと違うんですか」
「そうとも言えるし、そうやないとも言える」
「1つはリテラルで、もう1つはインスタンスや」

String string1 = "Hello"; //リテラル
String string2 = new String("Hello"); //インスタンス

「ええっ」
「そうなんですか」

先輩ガチレク発動

「newしてつくった文字列はな」
「メモリのヒープ領域におかれんねん」
「ヒープ領域…?(;^ω^)」
「ざっくり言うたら『材料の保管庫』って感じや」
「プログラムの実行に必要なデータを置いとくとこやな」
「あーなるほど」
「話もどすけどな」
「newして作った文字列はヒープ領域におかれるんに対して」
「代入演算子で作った文字列はヒープにおかれた後」
「その参照が文字列リテラルプールに登録される」
「モジレツリテラルプール?」
「せや」
「ここに登録されたんと同じ文字列が次に作られたとき、」
「プログラムは文字列リテラルプールに登録された文字列の
 参照を返して、新しいインスタンスはつくらへん」
「なんとなくわかってきましたわ」
「同じ文字列やったら同じインスタンスを使いまわすってことですね?」
「まあ、ざくっと言うたらそうや」
「そもそもインスタンスの作成はコンピュータにとって
 しんどい仕事やねん」
「せやから、よく使うStringクラスはそのしんどい仕事を
 なるべくせえへんようにできるようになっとる訳やな」
「ほへー」
「勉強なりました」
「ありがとうございました(*´ω`)」

参考

https://it-trend.jp/development_tools/article/32-0041
川場隆『Javaオブジェクト指向徹底解説』(秀和システム)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSLでjupyter+Javaを使うときにClassPathを指定する

JupyterLab+Javaを使う場合にクラスパスを設定するぞ.

設定ファイルはどこだ

$ jupyter kernelspec list

java       /path/to/jupyter/kernels/java
python3    /path/to/jupyter/kernels/python3

通常のJavaとは違うjava-libというkernelを作るぞ

$ cd /home/user_name/.local/share/jupyter/kernels/
$ mkdir java-lib
$ cd java-lib
$ ln -s ../java/ijava-1.3.0.jar
$ cp ../java/kernel.json ./
$ vi kernel.json

kernel.json
{
    "argv": [
        "java",
        "-Xmx8g",
        "-cp",
        "/path/to/lib/dir/*:/path/to/java-lib/ijava-1.3.0.jar",
        "io.github.spencerpark.ijava.IJava",
        "{connection_file}"
    ],
    "display_name": "Java-lib",
    "language": "java",
    "interrupt_mode": "message",
    "env": {

    }
}

できた.
以下のコードでクラスパスがズラズラ出てくれば成功.

Properties properties = System.getProperties();
String clsPath = properties.getProperty("java.class.path");
System.out.println(clsPath);

しかし,実行ファイルごとにクラスパスを変更することはできないようだ.
ま,特定のlibファイルにjarファイルを全部入れておくという罰当たりなやり方で何とかなりそう.

しかし,Eclipseに慣れすぎているので,補完があまり効かないJupyterLabでどこまでコードが書けるか自信がない・・・

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Chocolateyを使ったWindowsのJava環境最新化

ChocolateyでWindows10 64bitのJava開発環境を最新化します。
Chocolateyは、Ubuntu/Debian系のapt-getのWindows版といった感じのソフトです。
年に1度ほどする作業で、当然次にするときに忘れているので、メモしておきます。
記事「Chocolateyを使った環境構築の時のメモ」を参考にしています。

とあるチュートリアルに従ってChocolateyをインストールしてごく稀に使っているだけなので、素晴らしいソフトかまるで判断できないです。ただ、リリースノートがあまりされていないのが気になります。

手順

まずは、Powershellを管理者権限で起動します。コマンドプロンプトだと警告でるのでやめました。

インストール済パッケージ確認

choco list -loでインストール済みパッケージを一覧確認です。

Powershell管理者権限
> choco list -lo
adoptopenjdk8 8.242.8
chocolatey 0.10.15
maven 3.6.3
3 packages installed.

一括アップデート

choco upgrade all -yでインストール済みパッケージを一括でアップデートします。

Powershell管理者権限
choco upgrade all -y

個別アップデート(おまけ)

個別にパッケージをアップデートする場合はchoco upgrade [packageName]です。

Powershell管理者権限
choco upgrade [packageName]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSLでJupyterLab Javaを使う

Windows10でJupyter Lab+Javaを使いたかったので試してみた.

インストール

Jupyterインストール

$ sudo pip install jupyterlab widgetsnbextension
$ jupyter lab --generate_config
$ cd .jupyter/
$ emacs jupyter_notebook_config.py

jupyter_notebook_config.py
# c.NotebookApp.use_redirect_file = True
c.NotebookApp.use_redirect_file = False

Jupyter用JavaKernelのインストール

$ git clone https://github.com/SpencerPark/IJava.git
$ cd IJava/
$ ./gradlew installKernel

実行

$ jupyter lab
または,Windows上で以下のようなショートカットを作成
image.png

ショートカットを実行すると,ブラウザ上にJupyterLabが無事立ち上がる.
すごいすごい.

image.png

ブラウザ上にLauncherが立ち上がるので,Javaを選べばとりあえずは動く.
しかし,classpathの読み込み方がわからん.

image.png

ClassPathが設定できなきゃ何もできないなあ.
とりあえずClassPathの設定方法を調べよう.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10のWSLでJupyterLab+Javaを使う

Windows10でJupyterLab+Javaを使いたかったので試してみた.
Jupyter Notebook上でJavaが動いたらなんか便利そうじゃない?

インストール

Jupyterインストール

$ sudo pip install jupyterlab widgetsnbextension
$ jupyter lab --generate-config
$ cd .jupyter/
$ emacs jupyter_notebook_config.py

jupyter_notebook_config.py
# c.NotebookApp.use_redirect_file = True
c.NotebookApp.use_redirect_file = False

Jupyter用JavaKernelのインストール

$ git clone https://github.com/SpencerPark/IJava.git
$ cd IJava/
$ ./gradlew installKernel

実行

$ jupyter lab
または,Windows上で以下のようなショートカットを作成
image.png

ショートカットを実行すると,ブラウザ上にJupyterLabが無事立ち上がる.
すごいすごい.

image.png

ブラウザ上にLauncherが立ち上がるので,Javaを選べばとりあえずは動く.
しかし,classpathの読み込み方がわからん.

image.png

ClassPathが設定できなきゃ何もできないなあ.
とりあえずClassPathの設定方法を調べよう.

ClassPathの設定の仕方はこちら.
https://qiita.com/toritorix/items/6f1675166223960a1e85

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GradleでS3を使用する時にNoSuchFieldError:REQUIRES_LENGTHと出て困った話

発生状況

AWS SDK for Java を使用してS3にファイルアップロードしようとしたら下記のようなエラーが発生した

Exception in thread "main" com.amazonaws.AmazonClientException: Unable to complete transfer: REQUIRES_LENGTH
    at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.unwrapExecutionException(AbstractTransfer.java:286)
    at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.rethrowExecutionException(AbstractTransfer.java:265)
    at com.amazonaws.services.s3.transfer.internal.AbstractTransfer.waitForCompletion(AbstractTransfer.java:103)
    at core.AwsApplication.main(AwsApplication.java:64)
Caused by: java.lang.NoSuchFieldError: REQUIRES_LENGTH
    at com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1731)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.uploadInOneChunk(UploadCallable.java:168)
    at com.amazonaws.services.s3.transfer.internal.UploadCallable.call(UploadCallable.java:148)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:115)
    at com.amazonaws.services.s3.transfer.internal.UploadMonitor.call(UploadMonitor.java:45)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

ファイルアップロードのソースコードは公式を参照しているので間違いはないはず
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/HLuploadFileJava.html

build.gradleに追加するコードもMVNRepositoryから参照してるので大丈夫なはず
https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3/1.11.784

調べたこと

コンソールに表示されている下記のファイルを確認したら HandlerContextKeyクラスにあるはずのREQUIRES_RENGTHフィールドが存在していのが原因っぽい

com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1731)

解決方法

下記サイトで質問している内容が参考になりそう
https://stackoverflow.com/questions/49085110/error-in-using-aws-java-sdk-s3

読んでみたらaws-sdk-coreのライブラリもbuild.gradleに追加する必要がある...らしい

ってことでMVNRepositoryから下記を追加してみる
https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-core/1.11.784

build.gradleはこんな感じで記述してみた(aws-java-sdk-s3was-java-sdk-coreのバージョンは一緒じゃないとダメらしい)

build.gradle
dependencies {
...
...
-- 省略 --

    compile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.784'
    compile group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.784'

}

実行してみたら...

Object upload started
2020-05-22 11:20:42.603  WARN 19566 --- [anager-worker-1] com.amazonaws.util.Base64                : JAXB is unavailable. Will fallback to SDK implementation which may be less performant.If you are using Java 9+, you will need to include javax.xml.bind:jaxb-api as a dependency.
Object upload complete

ちゃんとアップロード完了したみたいです!
とりあえず解決しました

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AndroidStudio] ActionBarDrawerToggleのハンバーガーメニューの色変更

タイトルの通りです。
自分用メモ。

ハンバーガーメニューを白色にしたい場合

MainActivity.java
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer,toolbar,
                R.string.drawer_open,
                R.string.drawer_close);
        /* ハンバーガーメニューのdrawableをtoggleから取得 */
        DrawerArrowDrawable arrowDrawable = toggle.getDrawerArrowDrawable();
        /* 色の変更 */
        arrowDrawable.setColor(getResources().getColor(R.color.colorWhite));
     /* 色を変更したdrawableを再びセット */
        toggle.setDrawerArrowDrawable(arrowDrawable);

以上です。

他にいい方法があれば教えてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OpenTracing チュートリアル 前半

OpenTracing チュートリアル 前半

上記に公開されている中から、今回はJava のチュートリアルをやってみようと思います。

実行環境

[root@localhost ~]# cat /etc/redhat-release 
CentOS Linux release 7.7.1908 (Core)

[root@localhost ~]# java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

[root@localhost ~]# mvn -v
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /usr/local/apache-maven
Java version: 1.8.0_252, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.252.b09-2.el7_8.x86_64/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1062.9.1.el7.x86_64", arch: "amd64", family: "unix"

[root@localhost ~]# docker -v
Docker version 19.03.5, build 633a0ea

Jaeger のdocker コンテナを起動する

Jaeger のGetting Started で公開されているコマンドを参考にJaeger のコンテナを起動します。

[root@localhost java]# docker run -itd --name jaeger \
>   -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
>   -p 5775:5775/udp \
>   -p 6831:6831/udp \
>   -p 6832:6832/udp \
>   -p 5778:5778 \
>   -p 16686:16686 \
>   -p 14268:14268 \
>   -p 9411:9411 \
>   jaegertracing/all-in-one:1.8 \
>   --log-level=debug
Unable to find image 'jaegertracing/all-in-one:1.8' locally
1.8: Pulling from jaegertracing/all-in-one
b9b0c98e35fd: Pull complete 
48b3359c5f38: Pull complete 
Digest: sha256:c6b9104263c3d5aefee645181ca50ab5dd26fde41092dcdf6f026808a6af008d
Status: Downloaded newer image for jaegertracing/all-in-one:1.8
8138fc00c6ea7fcc4e619fb99f3980a17e2b2a517f2c43f92c75a9ab0026355c

各Port の役割は下記の通りとなっているようです。

Port Protocol Component Function
5775 UDP agent accept zipkin.thrift over compact thrift protocol (deprecated, used by legacy clients only)
6831 UDP agent accept jaeger.thrift over compact thrift protocol
6832 UDP agent accept jaeger.thrift over binary thrift protocol
5778 HTTP agent serve configs
16686 HTTP query serve frontend
14268 HTTP collector accept jaeger.thrift directly from clients
9411 HTTP collector Zipkin compatible endpoint (optional)

コンテナが起動できていることを確認できたら、Web ブラウザからJaeger UI にアクセスしてみます。

Jager_UI.png

OpenTracing のチュートリアルのソースをgit clone

下記に、チュートリアルのソースが公開されておりますので、ローカルリポジトリに複製します。

$ git clone https://github.com/yurishkuro/opentracing-tutorial

README.md に記載されている通りに、ビルドできるかを確認します。

[root@localhost java]# cd opentracing-tutorial/java
[root@localhost java]# mvn clean package
(中略)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:01 min
[INFO] Finished at: 2020-05-21T01:48:42+09:00
[INFO] ------------------------------------------------------------------------

無事、ビルドに成功しました。

Lesson 1 のソースをビルドして実行してみる

ディレクトリ構成確認

[root@localhost java]# cd src/main/java/lesson01/
[root@localhost lesson01]# tree
.
├── README.md
├── exercise
│   └── Hello.java
└── solution
    └── Hello.java

複製してきたソースには処理が記載されていないので、README.md を見つつ、ソースを編集

src/main/java/lesson01/exercise/Hello.java
package lesson01.exercise;

import com.google.common.collect.ImmutableMap;

import io.jaegertracing.internal.JaegerTracer;
import io.opentracing.Span;
import io.opentracing.Tracer;
import lib.Tracing;

public class Hello {

    private final Tracer tracer;

    private Hello(Tracer tracer) {
        this.tracer = tracer;
    }

    private void sayHello(String helloTo) {
        // Operation: tracer.buildSpan("operationName");
        // Generating trace information: tracer.buildSpan();
        // Trace start: .start();
        Span span = tracer.buildSpan("say-hello").start();

        // Set span tags: span.setTag("key", value);
        span.setTag("hello-to", helloTo);

        // this goes inside the sayHello method
        String helloStr = String.format("Hello, %s!", helloTo);

        // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2"));
        span.log(ImmutableMap.of("event", "string-format", "value", helloStr));
        System.out.println(helloStr);

        // Set span logs: span.log(ImmutableMap.of("key1", "value1"));
        span.log(ImmutableMap.of("event", "println"));

        // Trace end: span.finish
        span.finish();
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            throw new IllegalArgumentException("Expecting one argument");
        }
        String helloTo = args[0];
        // Service: Tracing.init("serviceName");
        try (JaegerTracer tracer = Tracing.init("hello-world")) {
            new Hello(tracer).sayHello(helloTo);
        }
    }
}
  • すぐに動作を確認したい場合、時間がない場合には、下記で短縮も可能です。
[root@localhost java]# cp src/main/java/lesson01/solution/Hello.java src/main/java/lesson01/exercise/Hello.java

ビルド

[root@localhost java]# mvn clean package
(中略)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  16.242 s
[INFO] Finished at: 2020-05-22T06:33:55+09:00
[INFO] ------------------------------------------------------------------------

実行

[root@localhost java]# ./run.sh lesson01.exercise.Hello Bryan
06:35:41.228 [main] DEBUG io.jaegertracing.thrift.internal.senders.ThriftSenderFactory - Using the UDP Sender to send spans to the agent.
06:35:41.346 [main] DEBUG io.jaegertracing.internal.senders.SenderResolver - Using sender UdpSender()
06:35:41.457 [main] INFO io.jaegertracing.Configuration - Initialized tracer=JaegerTracer(version=Java-1.1.0, serviceName=hello-world, reporter=CompositeReporter(reporters=[RemoteReporter(sender=UdpSender(), closeEnqueueTimeout=1000), LoggingReporter(logger=Logger[io.jaegertracing.internal.reporters.LoggingReporter])]), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-1.1.0, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false, useTraceId128Bit=false)
Hello, Bryan!

Jaeger UI でソース通りにトレース情報が生成できているかを確認

  • Service Name
  • Operation Name
  • Span Tag
  • Span Log

opentracing_turorial_001.png

opentracing_turorial_001_002.png

Lesson 2のソースをビルドして実行してみる

README.md を見つつ、ソースを編集

src/main/java/lesson02/exercise/Hello.java
package lesson02.exercise;

import com.google.common.collect.ImmutableMap;

import io.jaegertracing.internal.JaegerTracer;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import lib.Tracing;

public class Hello {

    private final Tracer tracer;

    private Hello(Tracer tracer) {
        this.tracer = tracer;
    }

    private void sayHello(String helloTo) {
        // Operation: tracer.buildSpan("operationName").start();
        // Generating trace information: .buildSpan();
        // Trace start: .start();
        Span span = tracer.buildSpan("say-hello").start();
        try (Scope scope = tracer.scopeManager().activate(span)) {
            // Set span tags: span.setTag("key", value);
            span.setTag("hello-to", helloTo);
            String helloStr = formatString(helloTo);
            printHello(helloStr);
        } finally {
            span.finish(); // Trace end: span.finish
        }
    }

    private String formatString(String helloTo) {
        // Operation: tracer.buildSpan("operationName").start();
        // Generating trace information: .buildSpan();
        // Trace start: .start(); 
        Span span = tracer.buildSpan("formatString").start();
        try (Scope scope = tracer.scopeManager().activate(span)) {
            String helloStr = String.format("Hello, %s!", helloTo);
            // Set span logs: span.log(ImmutableMap.of("key1", "value1", "key2", "value2"));
            span.log(ImmutableMap.of("event", "string-format", "value", helloStr));
            return helloStr;
        } finally {
            span.finish(); // Trace end: span.finish
        }
    }

    private void printHello(String helloStr) {
        // Operation: tracer.buildSpan("operationName").start();
        // Generating trace information: .buildSpan();
        // Trace start: .start(); 
        Span span = tracer.buildSpan("printHello").start();
        try (Scope scope = tracer.scopeManager().activate(span)) {
            System.out.println(helloStr);
            // Set span logs: span.log(ImmutableMap.of("key1", "value1"));       
            span.log(ImmutableMap.of("event", "println"));
        } finally {
            span.finish(); // Trace end: span.finish
        }
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            throw new IllegalArgumentException("Expecting one argument");
        }
        String helloTo = args[0];
        // Service: Tracing.init("serviceName");
        try (JaegerTracer tracer = Tracing.init("hello-world")) {
            new Hello(tracer).sayHello(helloTo);
        }
    }
}

ビルド

[root@localhost java]# mvn clean package
(中略)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.413 s
[INFO] Finished at: 2020-05-22T07:35:12+09:00
[INFO] ------------------------------------------------------------------------

実行

[root@localhost java]# ./run.sh lesson02.exercise.Hello Bryan
07:36:58.491 [main] DEBUG io.jaegertracing.thrift.internal.senders.ThriftSenderFactory - Using the UDP Sender to send spans to the agent.
07:36:58.637 [main] DEBUG io.jaegertracing.internal.senders.SenderResolver - Using sender UdpSender()
07:36:58.734 [main] INFO io.jaegertracing.Configuration - Initialized tracer=JaegerTracer(version=Java-1.1.0, serviceName=hello-world, reporter=CompositeReporter(reporters=[RemoteReporter(sender=UdpSender(), closeEnqueueTimeout=1000), LoggingReporter(logger=Logger[io.jaegertracing.internal.reporters.LoggingReporter])]), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-1.1.0, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false, useTraceId128Bit=false)
07:36:58.847 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: d9d0cc339032bb7e:e553869b15fef330:d9d0cc339032bb7e:1 - formatString
Hello, Bryan!
07:36:58.848 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: d9d0cc339032bb7e:b5937236a352f98b:d9d0cc339032bb7e:1 - printHello
07:36:58.848 [main] INFO io.jaegertracing.internal.reporters.LoggingReporter - Span reported: d9d0cc339032bb7e:d9d0cc339032bb7e:0:1 - say-hello

Jaeger UI でソース通りにトレース情報が生成できているかを確認

  • formatString
    • Operation Name
    • Span Log
  • printHello
    • Operation Name
    • Span Log

opentracing_turorial_002.png

opentracing_turorial_002_002.png

  • trace.scopeManager().active(span) makes the given span the currently active span. Once the scope is closed, the previous scope becomes current, thus re-activating previously active span in the current thread.
  • Scope is auto-closable, which allows us to use try-with-resource syntax.
  • If there is already an active span, it will act as the parent to the span created by buildSpan().
  • 和訳
  • trace.scopeManager().active(span) は、与えられたスパンを現在アクティブなスパンにします。スコープを閉じると、前のスコープがカレントになり、現在のスレッドで以前にアクティブだったスパンが再びアクティブになります。
  • スコープは自動で閉じることができるので、リソースとの試行錯誤の構文を使用することができます。
  • 既にアクティブなスパンがある場合は、そのスパンが buildSpan() で作成されたスパンの親として動作します。

という記載があるので、

処理順番 メソッド名 親子関係
1 sayHello
2 formatString
3 printHello

長くなりそうなので、lesson03, lesson04 は別の機会で別途記事を作成しようと思います。

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Kotlin】内容の重複したファイルを削除する【Java】

やりたいこと

あるディレクトリの中に内容の重複したファイルが大量に有る時、1つだけ残して重複したものを削除します。

やり方

ファイル全体を比較すると処理コストが高くて大変です。

そこで今回はファイルのハッシュ(ダイジェスト)を比較することとし、以下の方針で実装しました。

  1. ファイルのハッシュを取ってダイジェストを取得
  2. ダイジェストがSetに既存かチェック
  3. 存在していれば削除
  4. 存在していなければSetadd

サンプルコード

とりあえず動くサンプルは以下の通りです。

import java.io.File
import java.security.MessageDigest

val sha256 : MessageDigest = MessageDigest.getInstance("SHA-256")

fun getDigest(bytes: ByteArray): List<Byte> = sha256.digest(bytes).toList()

fun getFiles(pathToDir: String): List<File> = File(pathToDir).listFiles()?.toList() ?: emptyList()

fun main() {
    val files = getFiles(/* 処理対象ディレクトリのパス */)

    val set = HashSet<List<Byte>>()
    var count = 0

    files.forEach {
        val digest = getDigest(it.readBytes())

        if (set.contains(digest)) {
            if (it.delete()) {
                println("Deleted:\t${it.name}")
                count++
            } else {
                println("Fail delete:\t${it.name}")
            }
        } else {
            set.add(digest)
        }
    }

    println("\n\n$count deleted.")
}

実行結果

折り畳み
Deleted:    43_3のコピー.gif
Deleted:    46_3のコピー2.gif
Deleted:    70_1のコピー2.gif
Deleted:    94_1のコピー.gif
Deleted:    50_3のコピー2.gif
Deleted:    66_1のコピー.gif
Deleted:    95_1のコピー.jpg
Deleted:    58_3のコピー.gif
Deleted:    63_1のコピー.gif
Deleted:    32_1のコピー.jpg
Deleted:    55_3のコピー.gif
Deleted:    62_3のコピー.gif
Deleted:    49_3のコピー.gif
Deleted:    9_1のコピー2.gif
Deleted:    47_3のコピー.gif
Deleted:    96_1のコピー.jpg
Deleted:    71_1のコピー.gif
Deleted:    52_3のコピー2.gif
Deleted:    64_1のコピー2.gif
Deleted:    61_3のコピー.gif
Deleted:    56_3のコピー.gif
Deleted:    60_3のコピー2.gif
Deleted:    31_1のコピー.jpg
Deleted:    57_3のコピー2.gif
Deleted:    98_1のコピー2.jpg
Deleted:    34_1のコピー.jpg
Deleted:    68_1のコピー.gif
Deleted:    53_3のコピー.gif
Deleted:    42_3のコピー.gif
Deleted:    74_1のコピー2.gif
Deleted:    30_1のコピー.gif
Deleted:    36_1のコピー2.gif
Deleted:    65_1のコピー.gif
Deleted:    100_1のコピー.jpg
Deleted:    37_1のコピー.gif
Deleted:    35_1のコピー2.gif
Deleted:    45_3のコピー.gif
Deleted:    99_1のコピー.jpg
Deleted:    87_1のコピー2.jpg
Deleted:    33_1のコピー.jpg
Deleted:    73_1のコピー.gif
Deleted:    1_7のコピー.jpg
Deleted:    48_3のコピー.gif
Deleted:    54_3のコピー2.gif
Deleted:    51_3のコピー.gif
Deleted:    67_1のコピー.gif
Deleted:    93_1のコピー2.gif
Deleted:    44_3のコピー2.gif
Deleted:    72_1のコピー2.gif
Deleted:    97_1のコピー2.jpg


50 deleted.

解説

ハッシュの取り方

java.security.MessageDigestを利用しました。
これは特にライブラリ等を導入せずJava標準で使えます。

今回はテキトーにSHA-256を指定しましたが、「極限まで重複を回避したいぜ!」という場合はSHA-512を指定してあげればいいと思います。

重複管理

恐らくHashSetを使うのが一番簡単かつコストも低いと思います。
また、ByteArrayではequals周りに不安があるため、ここではListに変換して取り扱っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】Selenide+ChromeDriverでサクッと統合テスト入門<2020年5月更新>

はじめに

アプリケーションの機能を開発したら他の機能とうまく連動するか、どんな挙動か調べるために統合テスト(結合テスト)やりますよね。
今回はJavaで開発したWebアプリケーションの簡単な統合テストを目視じゃなくて、自動化しちゃおう(当たり前か)ということでSelenide+ChromeDriverを使ったハンズオンをやろうと思います。
スクリーンショット 2020-05-22 0.38.50.png

※本格的にテストやるならMockitoなど使ってMock呼んでテストする方がいいです。

開発環境

macOS Catalina 10.15.4
IntelliJ IDEA 2018.3.6
Google Chrome 81.0.4044.138
Selenide 5.2.2
aShot 1.5.3

準備

使うライブラリをpom.xmlに記述します。

pom.xml

<dependency>
    <groupId>com.codeborne</groupId>
    <artifactId>selenide</artifactId>
    <version>5.2.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>ru.yandex.qatools.ashot</groupId>
    <artifactId>ashot</artifactId>
    <version>1.5.3</version>
</dependency>

次にChromeDriverを使うためにドライバをダウンロードします。(以下リンク)
https://chromedriver.chromium.org

  1. Downloadsをクリック スクリーンショット 2020-05-22 0.20.42.png
  2. Chromeのバージョンに合わせてドライバを選択(今回は81.0.4044.138) スクリーンショット 2020-05-22 0.30.41.png
  3. MacOSならmac64.zipを選択しダウンロード後、任意の場所に格納(あとで使うのでパスを覚えておくスクリーンショット 2020-05-22 0.32.41.png

基本設定

・Chromeドライバのパスの設定
・ChromeDriverインスタンスの生成
これでSelenideを用いたChromeの自動操作が可能になります。

System.setProperty("webdriver.chrome.driver", "<ドライバのパス>/chromedriver");
WebDriver webDriver = new ChromeDriver();

最終行にclose()を書くことでウィンドウを閉じます。

webDriver().close();

基本操作

以下、テストに必要な操作の中から、基本的なものを説明します。

リンクに遷移

webDriver.get("https://hoge.com/");

もう一つメソッドがあります。

webDriver.navigate().to("https://hoge.com/");

【補足】
get()とnavigate().to()はほとんど同じメソッドだと思ってもらって構いません。両者の違いは、SPA(シングルページアプリケーション)を操作する際に出てきます。SPA内ではget()がページを更新して遷移するのに対し、navigate().to()はページを更新せずに遷移します。get()はブラウザ履歴やcookieを保持せず、navigate().toは保持します。SPAではnavigate().to()の方がより人間が操作してるのに近いテストを実施できるといえます。

戻る・進む

戻る

webDriver.navigate().back();

進む

webDriver.navigate().forward();

更新

更新

webDriver.navigate().refresh();

要素の取得

HTMLのid要素を取得

webDriver.findElement(By.id("hoge"));

class要素を指定できたりもしますが、取得結果が一意にならないことが多いのでid取得がおすすめです。

ボタンのクリック

ボタンのHTMLのid要素を取得し、クリック

webDriver.findElement(By.id("hoge")).click();

フォームの入力

フォームのHTMLのid要素を取得し、sendkeys()で入力

webDriver.findElement(By.id("hoge")).sendKeys("ほげほげ");

挙動は実際に画面に入力しているかのように一文字一文字入力されていきます。

フォームに入力されている値の消去

フォームのHTMLのid要素を取得し、clear()で消去

webDriver.findElement(By.id("hoge")).clear();

値の更新処理で既存の入力内容を消去したい場合に便利です。

スクリーンショットの撮影

一行目で全画面をスクショできるようにページサイズを最小化しています。最小化しないとChromeは自動でウィンドウサイズを調整してしまうので、画面全体がうまく写りません。三行目で画像のパスを指定しています。

webDriver.manage().window().setPosition(new Point(-2000, 0));

Screenshot screenshot = new AShot()
        .shootingStrategy(ShootingStrategies.viewportPasting(100))
        .takeScreenshot(webDriver);

ImageIO.write(screenshot.getImage(), "PNG", new File("<画像保存場所のパス>/<画像名>.png"));

(おまけ)統合テストコードの例

【テストシナリオ】

  1. hogeアプリケーションのログイン画面にアクセスする
  2. 管理者ユーザのメールアドレスとパスワードをフォームに入力
  3. ログインボタンをクリック
  4. 投稿リストの投稿1の編集ボタンをクリック
  5. フォームの投稿名を消去
  6. 投稿名に投稿2と入力
  7. 更新ボタンをクリック
  8. 更新完了後の画面をスクリーンショット
System.setProperty("webdriver.chrome.driver", "hoge/chromedriver");
WebDriver webDriver = new ChromeDriver();

webDriver.get("https://hoge.com/home");
webDriver.findElement(By.id("email")).sendKeys("admin@xx.xx.xx");
webDriver.findElement(By.id("password")).sendKeys("pass");
webDriver.findElement(By.id("loginButton")).click();
webDriver.navigate().to("https://hoge.com/edit?topicId=1");
webDriver.findElement(By.id("topicName")).clear();
webDriver.findElement(By.id("topicName")).sendKey("投稿2");
webDriver.findElement(By.id("updateButton")).click();
webDriver.manage().window().setPosition(new Point(-2000, 0));
Screenshot screenshot = new AShot()
    .shootingStrategy(ShootingStrategies.viewportPasting(100))
    .takeScreenshot(webDriver);
ImageIO.write(screenshot.getImage(), "PNG", new File("hoge/screenshot.png"));

webDriver.close();

おわりに

selenideで検索してもJavaじゃなくてPythonの情報が出てきちゃうのでまとめてみました。
統合テストの例は想像上のwebアプリケーションの想像上のテストなのであしからず。
ありがとうございました。

参考

Difference between webdriver.get() and webdriver.navigate()
Seleniumクイックリファレンス

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む