20200722のJavaに関する記事は8件です。

java7環境でもStringJoinerを使ってカンマ区切りで文字列を連結する方法

はじめに

私は現在、とあるSI企業に勤めていて、現在参画しているのがjavaの保守案件です。
保守開発中のシステムのバージョンが古く、残念ながらjava7を使用しています。

StringBuilderを使用して文字列連結(csv的な文字を生成するとき等)をする時に、java8以上だったらStringJoinerで簡単にできるのに……と思うことがたまにあります。
↓こういうの。

    for (String hoge : 何かのリスト) {
      if (sb.length() != 0) {
        sb.append(",");
      }
      sb.append("連結したい文字列");
    }

java7以下のプロジェクトに参画中で同じような悩みを抱えているSIerの人は私以外にもいるのではと思い、StringJoinerと同じ振る舞いをする自作クラスを作成し、java7環境下で使えるようにライブラリとして公開しました。

何でも良いので自作のライブラリを一般公開するという行為をしてみてかっただけです。

ということでjava7用にStringJoinerを自作しました

StringJoinerという名前のクラスを自作し、ライブラリとして公開しました。
実態としてはStringBuilderのラッパークラスです。
内部でStringBuilderを持っていて、delimiter、prefix、suffixをよしなに連結するだけのクラスです。
ソースはこちら↓
https://github.com/lovelyswallow/swallowJava8/blob/master/src/main/java/com/lovelyswallow/likejava8/util/StringJoiner.java

java7でStringJoinerを使うための準備

下記URLにアクセスしてjarを直接ダウンロードするなり、gradle等でjarの取得をするだけです。
java7ではjava.util.StringJoinerが使えないので、
代わりにcom.lovelyswallow.likejava8.util.StringJoinerをimportすれば、java標準のStringJoinerと同じ使い方ができます。
https://mvnrepository.com/artifact/io.github.lovelyswallow/swallowJava8

1.0はミスってjava12でコンパイルをしてしまっているので、ターゲットとしている肝心のjava7環境下では動作しません(笑)
使用する際は1.1以上をご利用ください。
1.1と1.1.1は中身が同じです。1.1.1はマイナーバージョンを上げるという行為をしたくて空リリースをしただけです。

StringJoinerの使い方

java標準のStringJoinerと同じメソッドを用意しているので、全く同じ使い方ができます。
java標準と違うのはコンストラクタの種類だけです。
今更説明する必要もないかもしれませんが、一応、使い方の例を書きました。

import com.lovelyswallow.likejava8.util.StringJoiner;

final class Test {
  public static void main(String[] args) {
    StringJoiner sj1 = new StringJoiner(",");
    sj1.add("hoge");
    sj1.add("fuga");
    sj1.add("piyo");
    System.out.println(sj1.toString()); // => hoge,fuga,piyo

    StringJoiner sj2 = new StringJoiner(",", "prefix", "suffix");
    sj2.add("hoge");
    sj2.add("fuga");
    sj2.add("piyo");
    System.out.println(sj2.toString()); // => prefixhoge,fuga,piyosuffix

    // 実態はStringBuilderのラッパークラスなので、コンストラクタでcapacityの指定をできます。
    StringJoiner sj3 = new StringJoiner(",", 100);
    StringJoiner sj4 = new StringJoiner(",", "prefix", "suffix", 100);
  }
}

最後に

最初に言った通り、以下の人に向けたライブラリとなっているので、現在ではあまり使い道はありません。

  • SIerの人
  • java7の現場に参画中
  • プロジェクトの都合でjavaのバージョンアップができない
  • java8で生まれたAPIを使いたい

同じ悩みを抱えているSIerの方は私以外にもいると信じて今回このライブラリを作りました。

今後はStringJoiner以外にもjava7環境向けに何かjava8っぽいクラスを作成したいと考えています。
とは言え、Streamっぽい振る舞いをする何か作ったところでラムダ式が使えないと微妙かもしれないけど。。。

がんばろう日本 :poop:

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

【#2 Java】よく聞くオブジェクト指向とは?

こんにちは、もえです。
今回はJavaを勉強しているとよく出てくる「オブジェクト指向」についてまとめてみました。

オブジェクトとは

オブジェクト指向は、大きなプログラムを記述しようとしたときに、人間の頭が追い付かず開発に時間がかかったり、完成しても不具合だらけのプログラムになってしまうことが多かったことから誕生した考え方です。
端的に言うと、「ソフトウェアを開発する時に用いる部品化の考え方のこと」です。
この考え方に沿って1つのソフトウェアを複数に部品化すると、プログラムが把握しやすくなり、「人間の頭が追い付かない状況」を避けることが出来るようになります。

オブジェクトとは、端的に言うと「もの」です。
例えば車で考えた時に、タイヤ、シート、エンジンなどひとつひとつがオブジェクトとなります。



では、オブジェクト指向とは何でしょうか。

オブジェクト指向プログラミングでは、プログラミングの機能や役割を区別し、それぞれの部品(オブジェクト)として組み合わせることで1つのプログラミングを作っています。
Javaでコーディングする際に定義するクラスも、クラスから生成されるインスタンスもオブジェクトです。

オブジェクト指向の3大機能は、以下の3つです。

  • カプセル化
    • 属性や操作を、一部の相手からは利用禁止にする機能
  • 継承
    • 過去に作った部分を流用し、新しい部品を簡単に作れる機能
  • 多様性
    • 似ている2つの部品を「同じようなもの」とみなし、「いいかげん」に利用できる機能

クラス

クラスは、オブジェクトを作成するための設計図です。
オブジェクトの属性(プロパティ)や振る舞い(メソッド)を記載する。
プロパティは、オブジェクトが持つデータ、メソッドはオブジェクトが持つ機能を指します。

自動車を例に考えてみると、クラスが自動車を作る元となる設計図にあたる。
また自動車の走る、曲がる、止まるといった機能がメソッド、車体サイズ、車体サイズや色、排気量といったスペックがプロパティに対応しています。

インスタンス

クラスを実体化したものがインスタンスです。
自動車の例で考えれば、設計図を基にして製造された自動車がインスタンスにあたります。
また、クラスからオブジェクトを生成することを「インスタンス化」と呼ぶ。

コンストラクタ

クラスをインスタンス化する際に初期化処理を行うための特別なブロックです。

  • 戻り値を持たないこと(戻り値の型も書かない)
  • クラスと同じ名前である

メソッド

メソッドとは一連の処理を一つにまとめたものです。
メソッドは覚えきれないほどたくさんありますが、自分で自作することが可能です。
というより、自分が実現したいプログラムを書く際、ほとんどの場合に自作のメソッドを作成します。

mainメソッド

プログラムを実行する時にシステムから最初に呼び出されるメソッドです。



今まで「オブジェクト指向って何だろう・・・」と思っていたので、今回少し理解することが出来て良かったです。
また投稿します!

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

【#1 Java】Javaの基本の基~勉強前の大前提~

こんにちは、もえです。
今回は私がプログラミング言語に触れるきっかけになったJavaについて書いていきたいと思います。

そもそもJavaとは

Javaとは、プログラムを作るために利用する、コンパイルが必要なプログラミング言語の一つです。
Javaを使えば、様々なコンピュータで動作する多様なプログラムを開発することが出来ます。

Javaを習得したプログラマーは現在市場で最も求められているので、将来を考えるならとりあえずJavaの勉強を始めてみるといいかもしれません。

ただし、Javaは他のプログラミング言語と比べ少し変わった特徴があります。

  • Javaの特徴
    • 学びやすく標準的な基本文法
    • 大規模開発を支援するオブジェクト指向に対応
    • 豊富に準備された便利な命令群
    • Windows、Mac、Linuxどんな環境でも同じように動作する汎用性

Javaはとにかくどこでも動く!をモットーに作られた言語です。
そのため特定のコンピュータが理解出来る機械語に翻訳するのではなく、どのコンピュータでも使える中間言語というものを作成します。

実行する時は、それぞれのコンピュータにインストールされたJava仮想マシン(JavaVM : Java Virtual Machine)が機械語に翻訳し、実行します。
プログラムを実行するのに「日本語→中国語」「日本語→ドイツ語」に翻訳するのではなくて、まずは必ず英語に翻訳してから他の言語に翻訳するというイメージを持つと分かりやすいと思います。

Javaのソースコードを書いてみる

Javaファイルは、テキストエディタで「.java」という拡張子を付ければ完成しますが、実行環境を用意しないと実行できません。
私はAdoptOpenJDKを使うを参考に環境を構築しました。

Javaの統合開発環境

Javaはファイルを作成後、ソースコードに対してコンパイルというプログラムの翻訳作業をして、バイトコード(byte code)に変換してから実行します。
ちなみにこの翻訳作業を行う翻訳ソフトウェアをコンパイラといます。
さらにコンパイル後、インタプリンタ(interpreter)というソフトウェアに対してバイトコードの実行を指示します。
このインタプリンタはJavaVMという仕組みを内部に持っており、バイトコードをCPUが理解出来るマシン語に変換します。

人間が書くプログラムは、このようにしてコンピュータが分かるように翻訳して初めて実行されますが、そのような設定を自らするような開発をすることはほとんどありません。

実際には、Java開発に必要な「コーディング」「コンパイル」「テスト」「デバッグ」など、プログラム開発の効率化を図れるようにした「統合開発環境(IDE)」を利用して行います。
これにはいくつか種類がありますが、自分に合った開発環境を整えましょう。
ちなみに私はEclipseとIntelliJ IDEAを使用しており、主にEclipseを使用しています。
開発環境の選択にあたっては、【初心者向け】Java開発ツールの種類を画像付きで解説を拝読しました。

フレームワーク

プログラム開発には統合開発環境という便利な環境があり、さらにその開発の補助となるフレームワークというものが存在します。
これは全体の処理の流れがあらかじめ実装されていて、その中の一部の具体的な処理を自分で実装してはめ込めるようになっているシステムです。
このフレームワークを活用することで、開発者は開発の効率化を図ることが出来ます。


Javaの基本的な話はこんな感じかな?
では、また投稿します!

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

【Java入門】条件分岐について(if文、if-else文、else if文、三項演算子、switch文)

目的

Java言語を含めたプログラミングの学習を始めたばかりの方、既学習者の方は復習用に、
今回は条件分岐について学ぶために書いています。

【Java入門目次】
変数と型
型変換
変数のスコープ
文字列の操作
配列の操作
演算子
・条件分岐 ←今ここ
・繰り返し処理(準備中)
・クラスについて(準備中)
・抽象クラス(準備中)
・インターフェース(準備中)
・カプセル化(準備中)
・モジュールについて(準備中)
例外処理について
ラムダ式について
Stream APIについて

条件分岐とは

ソースコード内である条件が満たされているかによって実行する処理を分けることです。
もし、〇〇ならばAの処理、△△ならばBの処理をする。といった感じです。

if文

条件式をもち、その条件の結果に応じた処理を行う場合に使用します。
条件式の結果はboolean値(true、false)で返ってきて、trueの時にif文内の処理が実行されます。

構文
if( 条件式 ) { 
  処理
};

例えば、条件式がtrueの場合。

ifがtrueの例
int num = 10;
if (num < 20) {
  System.out.println("numの値は20未満");
}
System.out.println("if文後の処理");

実行結果は以下になります。

numの値は20未満
if文後の処理

条件式を判定、結果はtrueなので、if文ブロック内の処理が実行され、その後、ifブロック外の処理が実行される。という流れになります。

条件式がfalseの場合。

ifがfalseの例
int num = 10;
if (num < 5) {
  System.out.println("numの値は5未満");
}
System.out.println("if文後の処理");

実行結果は以下になります。

実行結果
if文後の処理

条件式がfalseなのでif文ブロック内の処理が実行されず、その後の処理だけ実行されています。

また、if文の中にif文を記述する事も可能です。ネスト(入れ子)と言います。
ただ、あまり複数記述すると読みにくくなるので気をつけましょう。

ifのネスト
int num = 10;

if (num > 0) {
  System.out.println("numは正の値");
  if (num % 2 == 0) {
    System.out.println("numは偶数");
  }
}

値の比較時の注意

値が同じであるかを比較するには、==と記述します。=が1つだけの場合、関係演算子ではなく代入演算子になるので注意しましょう。

以下はコンパイルエラーになります。

無効なコード
int a = 20;
int b = 50;
if (a = b) { // int型のaにbを代入しているだけで、条件式が成り立っていない
  System.out.println("aとbの値は同じ");
}

値の比較は以下の様にします。

有効なコード
int a = 50;
int b = 50;
if (a == b) {
  System.out.println("aとbの値は同じ");
}
実行結果
aとbの値は同じ

条件式の箇所で代入を行ってもコンパイルエラーにはならないパターンもあります。

条件式で代入の例
boolean bool1 = false;
boolean bool2 = true;
if(bool1 = bool2) { // 代入の結果、boolean値が返ってくるので条件式として問題ない
  System.out.println("bool1: " + bool1);
  System.out.println("bool2: " + bool2);
}

falseのbool1にtrueのbool2を代入した結果、条件式がtrueになります。
よって、if文ブロック内の処理が実行されます。

実行結果
bool1: true
bool2: true

if-else文

条件式がtrueの時だけではなく、falseの時に行いたい処理を記述し、実行する事もできます。

構文
if( 条件式 ) { 
  処理1
} else {
  処理2
};

処理1は条件式がtrueの時に実行され、処理2は条件式がfalseの時に実行されます。

例えば、条件式がtrueの場合。

ifがtrueの例
String name1 = "柳田";
String name2 = "柳田";
if (name1 == name2) {
  System.out.println("name1とname2は同じ");
} else {
  System.out.println("name1とname2は同じではない");
}
System.out.println("if-else文後の処理");

実行結果は以下になります。

実行結果
name1とname2は同じ
if-else文後の処理

条件式がtrueなのでif文ブロック内の処理が実行されます。
そして、elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。

条件式がfalseの場合。

ifがfalseの例
String name1 = "クリスティアーノ・ロナウド";
String name2 = "リオネル・メッシ";
if (name1 == name2) {
  System.out.println("name1とname2は同じ");
} else {
  System.out.println("name1とname2は同じではない");
}
System.out.println("if-else文後の処理");

実行結果は以下になります。

実行結果
name1とname2は同じではない
if-else文後の処理

条件式がfalseなのでif文ブロック内の処理が実行されず、else文ブロックの処理が実行されています。
そして、if文ブロック外の処理が実行される。という流れになります。

これで条件式がfalseの場合の処理を実装することが出来ます。

else if文

今までは条件式が1つだけでしたが、else if文を用いる事で複数の条件式を使うことが出来ます。

構文
if( 条件式1 ) { 
  処理1
} else if ( 条件式2 ) {
  処理2
} else {
  処理3
};

処理1は条件式1がtrueの時に実行され、処理2は条件式2がtrueの時に実行され、処理3は1つ目と2つ目の条件式がfalseの時に実行されます。

else if文は上から順に条件式が評価され、ある条件がtrueであった場合にそのブロック内の処理文のみを実行します。

例えば、条件式ifがtrueの場合。

ifがtrueの例
String color = "red";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");

実行結果は以下になります。

実行結果
colorはred
else ifの例

1つ目の条件式がtrueなのでif文ブロック内の処理が実行されます。
そして、else if、elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。

次に、条件式else ifがtrueの場合。

else-ifがtrueの例
String color = "yellow";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");

実行結果は以下になります。

実行結果
colorはyellow
else ifの例

1つ目の条件式がfalseなのでif文ブロック内の処理が実行されません。
そして、2つ目の条件式がtrueなのでelse if文ブロック内の処理が実行されます。
elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。

最後に条件式の全てがfalseの場合。

条件式全てがfalseの例
String color = "blue";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");

実行結果は以下になります。

実行結果
colorはredでもyellowでもない
colorはblue
else ifの例

1つ目、2つ目と条件式の結果がfalseなので、elseブロック内の処理が実行されます。
そして、if文ブロック外の処理が実行される。という流れになります。

これで複数の条件判定によって処理を分けることが出来るようになります。

三項演算子

条件式の結果に応じた式を実行する演算子です。

構文
条件式 ? 式1 : 式2;

条件式がtrueを返した場合は式1を実行し、falseを返した場合は式2を実行します。

例えば、条件式がtrueの場合。

三項演算子の例
String name = "yamada";
String str = "名前の長さは";
str += name.length() >= 4 ?  "4以上です" : "3以下です";
System.out.println(str);

実行結果は以下になります。

実行結果
名前の長さは4以上です

name.length() >= 4が条件式になります。
trueであれば、4以上ですが、falseであれば3以下ですがstrに格納されている文字列と結合されます。

同じ処理をif-else文で記述すると以下の様になります。

if-elseの場合
String name = "yamada";
String str = "名前の長さは";
if (name.length() >= 4) {
  str += "4以上です";
} else {
  str += "3以下です";
}
System.out.println(str);

三項演算子の方がif-else文で記述するよりスッキリ書けますね。

switch文

式の評価結果と定数を比較して、一致した場合に処理が実行される。という多分岐処理を行うための方法です。

構文
switch ( 式 ) {
  case 定数1:
    処理1;
    break;
  case 定数2:
    処理2;
    break;
  default:
    処理3;
}

式の結果が定数1と一致していれば処理1が実行され、定数2と一致していれば処理2が実行されます。
一致するものがない場合、default以下の処理が実行されます。(defaultの記述は任意です)

switch文の例
String color = "blue";

switch (color) {
  case "red":
    System.out.println("colorはred");
    break;
  case "yellow":
    System.out.println("colorはyellow");
    break;
  case "blue":
    System.out.println("colorはblue");
    break;
  default:
    System.out.println("colorは" + color);
    break;
}

実行結果は以下になります。

実行結果
colorはblue

式の結果は"blue"という文字列であり、3つ目のcaseと一致しています。
よって、その中の処理が実行されます。

switch文の注意点

式のデータ型

switch文の式に記述可能な値は、char、byte、short、int、そのラッパークラス、enum、Stringのいずれかのデータ型の値ではないといけません。

それ以外の型が指定されているとコンパイルエラーになります。

switch文の式のエラー
double d = 2.0;
switch (d) { // Cannot switch on a value of type double. Only convertible int values, strings or enum variables are permitted
  // 省略
}

式の結果

式のデータ型を守っていたとして式の結果がnullであった場合、コンパイルは成功しても実行時に例外が発生してしまいます。

switch文の式の例外発生
String ex = null;
switch (ex) {
  case "a":
    System.out.println("a");
    break;
  case "b":
    System.out.println("b");
    break;
  default:
    System.out.println("nothing");
    break;
}
実行結果
Exception in thread "main" java.lang.NullPointerException
        at Condition.main(Condition.java:102)

()内で演算子を使う

()内で計算をしても問題はないです。

足し算や、

()で計算の例
int a = 0;
switch (a + 1) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
}
実行結果
1

デクリメントなど。

()で計算の例2
int a = 0;
switch (--a) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  default:
    System.out.println("該当数字はないです");
    break;
}
実行結果
該当数字はないです

ただ、()内で変数を宣言するとコンパイルエラーになります。

()で変数宣言してエラー
switch (int a = 0;) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
}

caseで指定する値

①式の結果のデータ型とcaseで指定しているデータ型が一致していなければコンパイルエラーとなります。

caseで指定する値のエラー
int num = 10;
switch (num) {
  case "0": // Type mismatch: cannot convert from String to int
    System.out.println("0");
    break;
  case "1": // Type mismatch: cannot convert from String to int
    System.out.println("1");
    break;
  case "2": // Type mismatch: cannot convert from String to int
    System.out.println("2");
    break;
}

②リテラル、定数ではない場合、コンパイルエラーとなります。

caseで指定する値のエラー2
int num = 10;
int a = 1;
int b = 2;
switch (num) {
  case a: // case expressions must be constant expressions
    System.out.println("1");
    break;
  case b: // case expressions must be constant expressions
    System.out.println("2");
    break;
  default:
    System.out.println("nothing");
    break;
}

この場合、変数であるaとbをcaseに指定しているためエラーになります。
final修飾子を付与して定数化するか、リテラルを指定しましょう。

caseで指定する値のエラー2修正ver
int num = 10;
final int a = 1;

switch (num) {
  case a:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
  default:
    System.out.println("nothing");
    break;
}

③nullを指定するとコンパイルエラーとなります。

caseで指定する値のエラー3
String name = "田中";

switch (name) {
  case "山田":
    System.out.println("山田");
    break;
  case null: // case expressions must be constant expressions
    System.out.println("null");
    break;
}

④break文の有無

break;というワードで、処理が実行された後にswitch文から抜けています。
もし忘れてしまっていた場合は次のcaseとの比較を初めてしまうので気をつけましょう。

breakを忘れた時
int num = 10;

switch (num) {
  case 0:
    System.out.println("0");
    break;
  case 10:
    System.out.println("10");
    // break;を書き忘れている
  default:
    System.out.println("nothing");
    break;
}

case 10 の時の処理が実行された後、break文がないためdefaultの処理も実行してしまいます。

実行結果
10
nothing

意図せぬ実行結果になってしまわないよう注意しましょう。

終わりに

プログラムの処理手順として条件に応じて処理を分岐させる方法を学びました。
ソースコードの可読性などを考慮して、状況によって使い分けていきたいですね。

参考サイト

処理の分岐
Javaのswitch文

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

JAVAでエンディアン変換

メモです。

バイナリファイルのエンディアン変換について下記参照してください。

http://pulasthisupun.blogspot.com/2016/06/reading-and-writing-binary-files-in.html

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

【Android 9.0 Pie Java】RecyclerViewの余白部分にsetOnTouchListenerを実装する

初めに

リスト表示に便利なRecyclerViewですが、デフォルトのままだと余白部分をタッチした際にイベントを発火させることができません。
RecyclerViewの余白部分をタッチしてソフトキーボードを閉じる為に実装を模索したので共有したいと思います。

32aeddc0c59703301a8fc30cf57374b6.gif

実装方法

まずRecyclerViewに

android:touchscreenBlocksFocus="true"

を追記します。

あとはonCreateViewやonCreatedViewでリスナーを実装するだけです。

Fragment.java
recyclerView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // キーボードを隠す
        InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS);
        // 背景にフォーカスを移す
        RecyclerView recyclerView = view.findViewById(R.id.recyclerView);
        recyclerView.requestFocus();
    }
});

以上です。

どなたかの参考になれたら幸いです。

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

【Android 9.0 Pie Java】RecyclerViewの余白部分にsetOnTouchListenerを実装してソフトキーボードを閉じる

初めに

リスト表示に便利なRecyclerViewですが、デフォルトのままだと余白部分をタッチした際にイベントを発火させることができません。
RecyclerViewの余白部分をタッチしてソフトキーボードを閉じる為に実装を模索したので共有したいと思います。

32aeddc0c59703301a8fc30cf57374b6.gif

実装方法

まずRecyclerViewに

android:touchscreenBlocksFocus="true"

を追記します。

fragment.xml
<LinearLayout
    android:id="@+id/scrollView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:isScrollContainer="false"
    app:layout_constraintBottom_toTopOf="@+id/footerBorder"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/headerBorder">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:touchscreenBlocksFocus="true"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>

あとはonCreateViewやonCreatedViewでリスナーを実装するだけです。

Fragment.java
RecyclerView recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // キーボードを隠す
        InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        // 背景にフォーカスを移す
        recyclerView.requestFocus();
        return false;
    }
});

以上です。

どなたかの参考になれたら幸いです。

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

【Effective Javaを読む】 第2章 項目2 『数多くのコンストラクタパラメータに直面した時にはビルダーを検討する』

数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

newする時にパラメータをたくさん渡してあげなきゃいけないようなクラスを作る時は
「ビルダー」を使うと可読性も安全性もあって良いよって話

サンプルコード

NutritionFactsという栄養成分を表すクラスが
一人前の分量、容器当たりの量、一人前のカロリー、etc たくさんのフィールドを持っている場合を例にして3つのパターンで考えてみる
・テレスコーピングコンストラクタ・パターン
 パラメータが多くなるとnewする時に引数に何を渡せば良いかわかりづらくなるし、可読性も下がってしまうのがデメリット

・JavaBeansパターン
 テレスコーピングコンストラクタ・パターンと違い可読性は上がるが、パラメータを設定している途中で不整合な状態ができてしまう

・ビルダーパターン
 テレスコーピングコンストラクタとJavaBeansのいいとこ取り!

例1
//テレスコーピングコンストラクタ・パターン
public class NutritionFacts{
    private final int servingSize;  //(mL)       必須
    private final int servings;     //(容器当たり)  必須
    private final int calories;     //           オプション
    private final int fat;          //(g)        オプション
    private final int sodium;       //(mg)       オプション
    private final int carbohydrate; //(g)        オプション

    public NutritionFacts(int servingSize, int servings){
        this(servingSize, servings, 0, 0, 0, 0);
    }

    public NutritionFacts(int servingSize, int servings, 
             int calories ){
        this(servingSize, servings, calories, 0, 0, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat ){
        this(servingSize, servings, calories, fat, 0, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat, int sodium ){
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat, int sodium, carbohydrate ){
        this.servingSize   = servingSize;
        this.servings      = servings;
        this.calories      = calories;
        this.fat           = fat;
        this.sodium        = sodium;
        this.carbohydrate  = carbohydrate;
    }
}

//newする時 見辛いね
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);

例2
//JavaBeansパターン
public class NutritionFacts{
    private int servingSize  = -1; //(mL)       必須
    private int servings     = -1; //(容器当たり)  必須
    private int calories     = 0;  //           
    private int fat          = 0;  //(g)        
    private int sodium       = 0;  //(mg)       
    private int carbohydrate = 0;  //(g)        

    public NutritionFacts(){ }

    //セッター
    public void setServingSize(int val)  { servingSize = val;}
    public void setServings(int val)     { servings = val;}
    public void setCalories(int val)     { calories = val;}
    public void setFat(int val)          { fat = val;}
    public void setSodium(int val)       { sodium = val;}
    public void setCarbohydrate(int val) { carbohydrate = val;}
}

//newする時 見易いけどsetしてる途中にアクセスされたらちょっと困る
NutritionFact cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

例3
//ビルダーパターン
public class NutritionFacts{
    private final int servingSize;  //(mL)       
    private final int servings;     //(容器当たり)
    private final int calories;     //           
    private final int fat;          //(g)        
    private final int sodium;       //(mg)       
    private final int carbohydrate; //(g)        

    public static class Builder{
        //必須パラメータ
        private final int servingSize;  //(mL)       
        private final int servings;     //(容器当たり)

        //オプションパラメータ
        private int calories     = 0;  //           
        private int fat          = 0;  //(g)        
        private int sodium       = 0;  //(mg)       
        private int carbohydrate = 0;  //(g)   

        public Builder(int servingSize, int servings){
            this.servingSize = servingSize;
            this.servings    = servings;
       }

       public Builder calories(int val){
            calories = val;
            return this;
       }

       public Builder fat(int val){
            fat = val;
            return this;
       }

       public Builder sodium(int val){
            sodium = val;
            return this;
       }

       public Builder carbohydrate(int val){
            carbohydrate = val;
            return this;
       }

       public NutritionFacts build() {
           return new NutritionFacts(this);
       }
    }

    private NutritionFacts(Builder builder){
         servingSize  = builder.servingSize;
         servings     = builder.servings;
         calories     = builder.calories;
         fat          = builder.fat;
         sodium       = builder.sodium;
         carbohydrate = builder.carbohydrate;
    }
}

//newする時 見易いし安全!
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
    calories(100).sodium(35).carbohydrate(27).build();

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