20200518のJavaに関する記事は10件です。

面倒くさがり屋なJavaエンジニアのためのGroovy入門

目次

  • Groovyとは
  • Groovyの特徴
    • Groovyのメリット
    • Groovyのデメリット
  • おわりに

Groovyとは

JVM上で動作する、動的型付けスクリプト言語


Groovyの特徴

なぜ、"面倒くさがり屋な" "Javaエンジニア" を対象にするのか...

それはGroovyには次のようなメリットがあるから。

1.Javaに比べてコード量が少なく済む
2.JavaのAPIも利用できる
3.充実したエコシステム(WebアプリケーションフレームワークのGrails、テスティングフレームワークのSpockなど)


Groovyのメリット - Javaに比べてコード量が少なく済む

  • 変数宣言/メソッド宣言

defで変数宣言ができる(型を明示することもできる)
defで宣言した場合、変数の型はObject型
publicメソッド宣言時にpublicは不要(メソッドのスコープはデフォルトでpublicのため)

Java
String helloWorld = "Hello World.";

public static void main(String[] args) {
    // do something
}
Groovy
def helloWorld = "Hello World."

//publicは省略可
static void main(String[] args) {
    // do something
}

// 戻り値の型はdefでもOK
static def main(String[] args) {
    //do something
}

// 戻り値の型は省略可
static main(String[] args) {
    //do something
}

// 引数の型も省略可
static main(args) {
    //do something
}

  • 文字列

${変数}の形で、変数を文字列に埋め込める

Java
String name = "Michael";
System.out.println("Hello " + name + "!");

// 出力結果
// Hello Michael!
Groovy
def name = "Michael"
println "Hello ${name}!"

// 出力結果
// Hello Michael!

  • List, Mapの初期化

Listの初期化は[]
Mapの初期化は[:]

Java
List<String> list = new ArrayList<>();
Map<String, String> map = new HashMap<>();
Groovy
def list = []
def map = [:] // 型はLinkedhashMapになる

  • コレクションの操作

クロージャーが便利
itはクロージャーに渡される引数を表す暗黙の変数(下の例ではnumbersリストの1つ1つの要素)

Java
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> odds = numbers.stream().filter(number -> number % 2 != 0).collect(Collectors.toList());
System.out.println(odds);

// 出力結果
// [1, 3, 5]
Groovy
def numbers = [1, 2, 3, 4, 5] 
def odds = numbers.findAll { it % 2 != 0 } 
// def odds = numbers.findAll { number -> number != 0 }
println odds

// 出力結果
// [1, 3, 5]

  • DB操作(MySQL)

@GrabでGrapeという構成管理ツールを使用して外部リポジトリ(Mavenリポジトリなど)からライブラリを取得できる
groovy.sql.Sqlクラスが便利

personテーブル

person_id first_name last_name
1 Michael Jordan
2 Michael Jackson
Java
// mysql-connector-javaをダウンロードし、クラスパスに追加

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sampledb", "root", "root");
// first_nameがMichaelのレコードのlast_nameを取得
PreparedStatement pstmt = conn.prepareStatement("SELECT last_name FROM person WHERE first_name = ?");
pstmt.setString(1, "Michael");
ResultSet rs = pstmt.executeQuery();
// 取得したレコードのlast_nameをコンソールに出力
while(rs.next()) {
    System.out.println(rs.getString("last_name"));
}

// 出力結果
// "Jordan"
// "Jackson"
Groovy
// Grapeを使用して外部リポジトリからmysql-connector-javaを取得
@GrabConfig(systemClassLoader=true)
@Grab("mysql:mysql-connector-java:5.1.49")

def sql = Sql.newInstance("jdbc:mysql://localhost:3306/sampledb", "root", "root", "com.mysql.jdbc.Driver")
// first_nameがMichaelのレコードのlast_nameを取得
def rows = sql.rows("SELECT last_name FROM person WHERE first_name = ?", ["Michael"])
// 取得したレコードのlast_nameをコンソールに出力
rows.each {
    println it.last_name
}

// 出力結果
// "Jordan"
// "Jackson"

Groovyのデメリット

  • コンパイル時に型チェックができない

動的型付け言語であるため、型を宣言せず、defで宣言した変数やクロージャーの引数については実行時に型チェックがされるため、型が原因のエラーについては実行時まで指摘されない。

  • バージョンによってはJavaの構文が一部サポートされていない

try-with-resource文やラムダ式等の一部の構文について、2系ではサポートされていない。
バージョン3系ではこれらもサポートされているが、リリースされたのが今年の2月のため、Groovyを使用するフレームワークやライブラリについては最新バージョンでも2.5系を使っている可能性がある。


おわりに

GroovyはJavaに比べてコード量が少なく済み、開発効率のアップにつながることが期待できます。
また、Javaエンジニアにとっては学習コストは低く、習得までさほど時間はかからないでしょう。(私も3か月ほどで習得できました。)
もしJavaのコードを冗長に感じていたり、より効率的に開発したいと思っていたりするようなら、Groovyを試してみてはいかがでしょうか?


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

NLP4J [001b] Java で 形態素解析(kuromojiを利用)

Index

kuromoji とは

Javaで開発したオープンソース日本語形態素解析エンジンです。

kuromoji | Atilika
https://www.atilika.com/ja/kuromoji/

Maven

<dependency>
    <groupId>org.nlp4j</groupId>
    <artifactId>nlp4j-core</artifactId>
    <version>1.3.0.0</version>
</dependency>
<dependency>
    <groupId>org.nlp4j</groupId>
    <artifactId>nlp4j-kuromoji</artifactId>
    <version>1.3.0.0</version>
</dependency>

コード

package example;

import nlp4j.Document;
import nlp4j.Keyword;
import nlp4j.impl.DefaultDocument;
import nlp4j.krmj.annotator.KuromojiAnnotator;

public class HelloKuromojiNLP1 {

    public static void main(String[] args) throws Exception {
        // 自然文のテキスト
        String text = "今日はいい天気です。";

        Document doc = new DefaultDocument();
        // 属性「text」としてセットする
        doc.putAttribute("text", text);

        // kuromoji アノテーター
        KuromojiAnnotator annotator = new KuromojiAnnotator();
        // 処理対象の属性を指定
        annotator.setProperty("target", "text");
        // 形態素解析処理
        annotator.annotate(doc); // throws Exception

        // キーワードの出力
        for (Keyword kwd : doc.getKeywords()) {
            System.err.println(kwd);
        }
    }
}

結果

今日 [facet=名詞, str=今日]
は [facet=助詞, str=は]
いい [facet=形容詞, str=いい]
天気 [facet=名詞, str=天気]
です [facet=助動詞, str=です]
。 [facet=記号, str=。]

Index

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

Spring Boot + Spring Data JPA にて getOne, findById, クエリメソッドの挙動を確認する

概要

  • Spring Boot + Spring Data JPA にて JpaRepository#getOne, CrudRepository#findById, クエリメソッド HogeRepository#findByFoo の挙動を確認する

メソッドの説明

JpaRepository#getOne

JpaRepository#getOne は遅延取得 (laze fetch) するメソッド。

JpaRepository (Spring Data JPA 2.2.7.RELEASE API) - Javadoc 日本語訳

T getOne(ID id)
指定された識別子を持つエンティティへの参照を返します。JPA 永続性プロバイダーの実装方法によっては、これは常にインスタンスを返し、最初のアクセスで EntityNotFoundException をスローする可能性が非常に高くなります。それらのいくつかは、無効な識別子をすぐに拒否します。

パラメーター :
id - null であってはなりません。

戻り値 :
指定された識別子を持つエンティティへの参照。

関連事項 :
for details on when an exception is thrown.

JpaRepository#getOne は EntityManager#getReference を呼び出している。

EntityManager (Java(TM) EE 8 Specification APIs)

T getReference(Class entityClass, Object primaryKey)
Get an instance, whose state may be lazily fetched.

CrudRepository#findById

CrudRepository (Spring Data Core 2.2.7.RELEASE API) - Javadoc 日本語訳

Optional findById(ID id)
ID でエンティティを取得します。

パラメーター :
id - null であってはなりません。

戻り値 :
指定された ID を持つエンティティ、または見つからない場合は Optional#empty()

例外 :
IllegalArgumentException - id が null の場合。

HogeRepository#findByFoo

今回作成する Hoge エンティティクラスの ID (主キー) である foo カラムの値を引数としてエンティティを取得するクエリメソッド。
クエリメソッドは Spring Data の命名規則に沿ったメソッド名を指定することで処理の実装が自動生成される仕組み。

Spring Data JPA 5.3. クエリメソッド - リファレンスドキュメント - 日本語訳

JPA モジュールは、クエリを文字列として手動で定義すること、またはメソッド名から派生させることをサポートしています。

6.3. データベースアクセス(JPA編) — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.5.1.RELEASE documentation

Spring Dataが定めた命名規約に則ったメソッド名にすることで実行するQuery(JPQL)を指定する。
Spring Data JPAの機能によってメソッド名からJPQLが生成される。
ただし、メソッド名からJPQLを作成できるのはSELECTのみで、UPDATEおよびDELETEのJPQLは生成できない。

サンプルコード

ソースコード一覧

├── build.gradle
├── settings.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── Hoge.java
        │           ├── HogeController.java
        │           ├── HogeRepository.java
        │           └── HogeService.java
        └── resources
            ├── application.properties
            └── data.sql

build.gradle

plugins {
  id 'org.springframework.boot' version '2.2.7.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}

group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'

repositories {
  mavenCentral()
}

dependencies {
  // Spring
  implementation 'org.springframework.boot:spring-boot-starter-web'
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  // Lombok
  compileOnly 'org.projectlombok:lombok'
  annotationProcessor 'org.projectlombok:lombok'
  // H2 Database
  runtimeOnly 'com.h2database:h2'
}

settings.gradle

rootProject.name = 'my-app'

src/main/java/com/example/Hoge.java

package com.example;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * DB テーブルの1レコード分に相当。
 */
@Data // Lombok で getter setter など便利なメソッドを自動生成
@Entity // JPA エンティティとして扱う
public class Hoge {

  @Id // JPA にこの変数をオブジェクトの ID (主キー) だと認識させる
  private String foo;

  private String bar;
}

src/main/java/com/example/HogeRepository.java

package com.example;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * DB アクセス用リポジトリ。
 * Spring Data JPA が標準で提供するメソッドが自動生成される。
 */
@Repository
public interface HogeRepository extends JpaRepository<Hoge, String> { // エンティティと主キーの型を指定

  // Spring Data JPA の命名規則に沿ったクエリメソッドを定義
  // 中身が自動生成される
  public Hoge findByFoo(String foo);
}

src/main/java/com/example/HogeService.java

サービスクラス。リポジトリのメソッドをコールする。

package com.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
@Transactional
@Slf4j // org.slf4j.Logger 型の static final 変数 log を自動生成
public class HogeService {

  @Autowired
  private HogeRepository repository;

  public Hoge getOne(String id) {
    // JpaRepository#getOne
    log.debug("Before: JpaRepository#getOne");
    Hoge hoge = repository.getOne(id);
    log.debug("After: JpaRepository#getOne");
    return hoge;
  }

  public Hoge findById(String id) {
    // CrudRepository#findById
    log.debug("Before: CrudRepository#findById");
    Optional<Hoge> opt = repository.findById(id);
    log.debug("After: CrudRepository#findById");
    return opt.orElseThrow();
  }

  public Hoge findByFoo(String foo) {
    // HogeRepository#findByFoo
    log.debug("Before: HogeRepository#findByFoo");
    Hoge hoge = repository.findByFoo(foo);
    log.debug("After: HogeRepository#findByFoo");
    return hoge;
  }
}

src/main/java/com/example/HogeController.java

コントローラークラス。サービスのメソッドをコールする。

package com.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@SpringBootApplication
@RestController
@Slf4j // org.slf4j.Logger 型の static final 変数 log を自動生成
public class HogeController {

  public static void main(String[] args) {
    SpringApplication.run(HogeController.class, args);
  }

  @Autowired
  private HogeService service;

  @GetMapping("/getOne/{foo}")
  public Map getOne(@PathVariable("foo") String foo) {

    // エンティティを取得
    log.debug("Before: HogeService#getOne");
    Hoge hoge = service.getOne(foo);
    log.debug("After: HogeService#getOne");

    // エンティティから値を取り出す
    log.debug("Before: Hoge#getFoo, Hoge#getBar");
    Map result = Map.of(hoge.getFoo(), hoge.getBar());
    log.debug("After: Hoge#getFoo, Hoge#getBar");
    return result;
  }

  @GetMapping("/findById/{foo}")
  public Map findById(@PathVariable("foo") String foo) {

    // エンティティを取得
    log.debug("Before: HogeService#findById");
    Hoge hoge = service.findById(foo);
    log.debug("After: HogeService#findById");

    // エンティティから値を取り出す
    log.debug("Before: Hoge#getFoo, Hoge#getBar");
    Map result = Map.of(hoge.getFoo(), hoge.getBar());
    log.debug("After: Hoge#getFoo, Hoge#getBar");
    return result;
  }

  @GetMapping("/findByFoo/{foo}")
  public Map findByFoo(@PathVariable("foo") String foo) {

    // エンティティを取得
    log.debug("Before: HogeService#findByFoo");
    Hoge hoge = service.findByFoo(foo);
    log.debug("After: HogeService#findByFoo");

    // エンティティから値を取り出す
    log.debug("Before: Hoge#getFoo, Hoge#getBar");
    Map result = Map.of(hoge.getFoo(), hoge.getBar());
    log.debug("After: Hoge#getFoo, Hoge#getBar");
    return result;
  }
}

src/main/resources/application.properties

application.properties
# Spring Framework と Hibernate ORM 等のログを出力するように指定
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql=TRACE
logging.level.org.springframework.orm.jpa=DEBUG
logging.level.com.example=DEBUG

# Open EntityManager in View パターンを使う
spring.jpa.open-in-view=true

src/main/resources/data.sql

-- 初期データを DB に追加
INSERT INTO hoge (foo, bar) VALUES ('myfoo', 'mybar');

Spring Boot アプリケーションを起動

Java 11 (AdoptOpenJDK 11.0.7+10) + Gradle 6.4.1 で Spring Boot アプリケーションを起動する。

$ gradle bootRun

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.7.RELEASE)

起動時のログを見る。

Spring Boot 2.2.7 + Spring 5.2.6 が使われている。

com.example.HogeController               : Running with Spring Boot v2.2.7.RELEASE, Spring v5.2.6.RELEASE

Hibernate ORM core version 5.4.15.Final が使われている。

o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.15.Final
o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect

エンティティクラスの定義から自動的にテーブルが作成される。

org.hibernate.SQL                        : create table hoge (foo varchar(255) not null, bar varchar(255), primary key (foo))
o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

アクセスしてそれぞれのメソッドの挙動を見る

JpaRepository#getOne

curl でアクセスする。

$ curl http://localhost:8080/getOne/myfoo

Spring Boot のログを確認する。

JpaRepository#getOne で Hoge エンティティを取得する際にではなく、取得した Hoge エンティティのフィールドにアクセスする際に select 文が発行されている (lazy fetch による遅延取得)。

o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
com.example.HogeController               : Before: HogeService#getOne
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(1004472706<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.HogeService.getOne]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@2c01e862]
com.example.HogeService                  : Before: JpaRepository#getOne
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(1004472706<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
com.example.HogeService                  : After: JpaRepository#getOne
o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(1004472706<open>)]
o.s.orm.jpa.JpaTransactionManager        : Not closing pre-bound JPA EntityManager after transaction
com.example.HogeController               : After: HogeService#getOne
com.example.HogeController               : Before: Hoge#getFoo, Hoge#getBar
org.hibernate.SQL                        : select hoge0_.foo as foo1_0_0_, hoge0_.bar as bar2_0_0_ from hoge hoge0_ where hoge0_.foo=?
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [myfoo]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([bar2_0_0_] : [VARCHAR]) - [mybar]
com.example.HogeController               : After: Hoge#getFoo, Hoge#getBar
o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor

CrudRepository#findById

curl でアクセスする。

$ curl http://localhost:8080/findById/myfoo

Spring Boot のログを確認する。

CrudRepository#findById で Hoge エンティティを取得する際に select 文が発行されている。

o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
com.example.HogeController               : Before: HogeService#findById
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(794705340<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.HogeService.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@2199c627]
com.example.HogeService                  : Before: CrudRepository#findById
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(794705340<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
org.hibernate.SQL                        : select hoge0_.foo as foo1_0_0_, hoge0_.bar as bar2_0_0_ from hoge hoge0_ where hoge0_.foo=?
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [myfoo]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([bar2_0_0_] : [VARCHAR]) - [mybar]
com.example.HogeService                  : After: CrudRepository#findById
o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(794705340<open>)]
o.s.orm.jpa.JpaTransactionManager        : Not closing pre-bound JPA EntityManager after transaction
com.example.HogeController               : After: HogeService#findById
com.example.HogeController               : Before: Hoge#getFoo, Hoge#getBar
com.example.HogeController               : After: Hoge#getFoo, Hoge#getBar
o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor

HogeRepository#findByFoo

curl でアクセスする。

$ curl http://localhost:8080/findByFoo/myfoo

Spring Boot のログを確認する。

HogeRepository#findByFoo で Hoge エンティティを取得する際に select 文が発行されている。

o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
com.example.HogeController               : Before: HogeService#findByFoo
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(1242780251<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.HogeService.findByFoo]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@44d4b569]
com.example.HogeService                  : Before: HogeRepository#findByFoo
org.hibernate.SQL                        : select hoge0_.foo as foo1_0_, hoge0_.bar as bar2_0_ from hoge hoge0_ where hoge0_.foo=?
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [myfoo]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([foo1_0_] : [VARCHAR]) - [myfoo]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([bar2_0_] : [VARCHAR]) - [mybar]
com.example.HogeService                  : After: HogeRepository#findByFoo
o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(1242780251<open>)]
o.s.orm.jpa.JpaTransactionManager        : Not closing pre-bound JPA EntityManager after transaction
com.example.HogeController               : After: HogeService#findByFoo
com.example.HogeController               : Before: Hoge#getFoo, Hoge#getBar
com.example.HogeController               : After: Hoge#getFoo, Hoge#getBar
o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor

参考資料

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

java の抽象クラスについて

java のabstract の理解が進んでいなかったので学習した。

特徴

・直接のインスタンス生成が出来ない
・サブクラスにオーバーライドを強制する
・サブクラスでコンストラクタを記述する必要がある

sample.java
abstract class Abst_sample {
    abstract void abstractMethod(int num, String str);
    void nonAbstractMethod() {
        System.out.println("非抽象メソッドより出力");
    }
}
public class sample extends Abst_sample {
    public static void main(String[] args) {
        sample aaa = new sample();   
// 継承したあとで、自身のインスタンスを生成してabstractMethod を呼び出している。
        aaa.abstractMethod(3, "Test");
    }
    @Override
    public void abstractMethod(int num, String str) {
        System.out.println("引数int num = " + num + " / 引数String str = "+ str);
    }
}

「こういうメソッドを使いなさい」を指示を出すイメージかな。

多人数で開発をするとなると、こういう機能も必要になってくるんだろう。

覚えておいて損はないな。

参考

https://www.sejuku.net/blog/22689

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

Javaの配列での複数を求める場合

【例】

Main.java
class xxxx {
  public static void main(String[] args) {
    int[] numbers = {1, 6, 11, 16, 21, 26};

    int oddNumber = 0;
    int evenNumber = 0;

    for (int number : numbers) {
      if (number % 2 == 0) {
        evenNumber += number;
      } else {
        oddNumber += number;
      }
    }

    System.out.println("奇数の合計は" + oddNumber + "です");
    System.out.println("偶数の合計は" + evenNumber + "です");
  }
}

上記の結果は奇数の合計は33です
偶数の合計は48です
となります。
配列numbersの要素を1つずつ取得し、その要素の値が
奇数であれば変数oddNumberで
偶数であれば変数evenNumberとしています。
偶数であるか奇数であるかの判定は、if文で「%」を用いています。
「% 2 == 0」とすることでk「evenNumber += number;」で偶数であるか
違えばelseの「oddNumber += number;」が実行されます。

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

Javaの配列

配列

配列とは、複数の値をまとめられることです。

配列の変数定義

配列を扱う場合には、配列型の変数に配列を代入します。
配列の変数定義int型とString型

int[]
String[]

int型は数値を要素に持つ配列です。
String型は文字列を要素に持つ配列です。Stringの頭文字は大文字です。
int型の配列の例

Main.java
int[] numbers = {1,5,10};

String型の配列の例

Main.java
String[] names = {"佐藤","鈴木","高橋"};

配列の要素には、前から順に「0, 1, 2・・・」と数字が割り振られています。
配列の各要素は、配列名[インデックス番号]とすることで取得することができます。
【例】

Main.java
String[] names = {"佐藤","鈴木","高橋"};
  System.out.println("名前は"+names[0]+"です");

配列の要素の上書き

Main.java
String[] names = {"佐藤","鈴木","高橋"};
  System.out.println("名前は"+names[0]+"です");
  names[0] = "上野";
  System.out.println("名前は"+names[0]+"です");

names[インデックス] = "要素";で上書きできます。
上記の例だとコンソールの出力結果は佐藤と上野になります。

配列の繰り返し処理

for文を使って繰り返し処理ができます。
【例】

Main.java
String[] names = {"佐藤","鈴木","高橋"};
  for (int x = 0;x < 3;x++){
  System.out.println("名前は"+names[x]+"です");
}

上記の例だとインデックスの0から2までの3つをnamesから呼び出しています。

length

lengthとは要素の数を数えるという機能です。
上記のfor文とlengthを使って、繰り返し処理ができます。
先ほどのfor文の条件式x<3を配列.lengthにすることで書き換えることができます。
【例】

Main.java
String[] names = {"佐藤","鈴木","高橋"};
  for (int x = 0;x < names.length;x++){
  System.out.println("名前は"+names[x]+"です");
}

上記のように記述すれば、配列の要素数を気にする必要がなくなります。
なので、こちらの方が使いやすいと思います。
ですが、もっとシンプルなfor文もあります。それは配列拡張for文です。

配列拡張for文

for文は配列用に拡張for文があります。これを使えば、先ほどのfor文をよりシンプルに書くことができます。

Main.java
for (データ型 変数名:配列名) {
  繰り返す処理;
}

【例】

Main.java
String[] names = {"佐藤","鈴木","高橋"};
  for (String name:names){
  System.out.println("名前は"+name+"です");
}

上記の例だとStringがデータ型、nameが変数名、namesが配列名です。
先ほどまでのlengthを使ったfor文と比較して、拡張for文では変数に配列の要素自体が代入されます。
私が理解するためにだらだら書きましたが、これが一番使いやすいかなと思います。

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

JavaでTODOアプリを制作しよう1 MVCの簡単な説明

こんにちは。

タイトルの通り、JavaでTODOアプリを作る方法を書いていきます。
今回は実際にコードを書く前にJavaではどんな風な値が流れているのかを説明したいと思います。

MVCとは?

MVCとは

Model...(データベースとのやりとりをしたり、処理をしたりする)
View...(HTML/CSSとかを使ってユーザーへ実際に表示される画面)
Controller...(Modelにデータの処理を頼んだり、返ってきたデータをViewに渡す)

こんな感じでそれぞれが役割を持っています。

ではJavaのMVCはどうなっているのでしょうか?

View, Controller, Service, Repository, Entity

JavaではModelの部分をService, Repository, Entityというクラスで行う事が一般的のようです。

簡単にTODO登録の流れを書くと

  1. View上で登録ボタンが押されて登録内容が送信される。

  2. 登録内容がControllerのメソッドに渡される。

  3. ControllerはServiceクラスに登録内容を渡す。

  4. Serviceクラスは登録内容をEntityクラスの変数にあてはめてRepositoryクラスのメソッドでデータベースに保存する。

みたいな流れです。

正直これだけだとなかなか掴めないと思うので、今後の記事で実際に一つ一つ解説しながら進めていこうと思います!

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

JavaはExcelを画像、html、XPS、XML、CSV、PostScript、PCLに変換します

Excel文書の日常の運用では、さまざまな作業場面のニーズを満たすために、文書の形式を変換する必要があることがよくあります。この記事では、Javaプログラムでコードを使用してExcelを画像、html、XPS、XML、CSVに変換する方法を示します。

使用ツール: Free Spire.XLS for Java(無料版)

JARファイルのインポート方法
方法1: Free Spire.XLS for Javaパッケージをダウンロードして解凍し、Spire.Xls.jarパッケージをlibフォルダーからJavaアプリケーションにインポートします。
方法2: mavenを使用している場合は、pom.xmlファイルに次の依存関係を追加する必要があります。

<repositories>
        <repository>
            <id>com.e-iceblue</id>
            <name>e-iceblue</name>
            <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url>
        </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.xls.free</artifactId>
        <version>2.2.0</version>
    </dependency>
</dependencies>

Javaコード例:

import com.spire.xls.*;

public class ExcelToImg {
    public static void main(String[] args) {
        //Excelワークシートを読み込む
        Workbook wb = new Workbook();
        wb.loadFromFile("input.xlsx");

        //ワークシートを取得
        Worksheet sheet = wb.getWorksheets().get(0);

        //画像としてExcelワークシートを保存
        sheet.saveToImage("ToImg.png");
        //Excelで指定したセルのデータ範囲を画像として保存する
        //sheet.saveToImage("ToImg2.png",8,1,30,7);

        //ExcelをHTMLとして保存
        sheet.saveToHtml("ToHtml.html");

        //ExcelをXPSとして保存
        sheet.saveToFile("ToXPS.xps", String.valueOf(FileFormat.XPS));

        //ExcelをCSVとして保存
        sheet.saveToFile("ToCSV.csv", String.valueOf(FileFormat.CSV));

        //ExcelをXMLとして保存
        sheet.saveToFile("ToXML.xml", String.valueOf(FileFormat.XML));

        //ExcelをPostScriptとして保存
        sheet.saveToFile("ToPostScript.postscript", String.valueOf(FileFormat.PostScript));

        //ExcelをPCLとして保存
        sheet.saveToFile("ToPCL.pcl", String.valueOf(FileFormat.PCL));

    }
 }

ドキュメントの変換結果:
convert.png

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

localhost:8080で表示されるログイン画面

原因の正体はSpringSecurity

SpringBootを使ってWEBアプリケーションを開発するとき、localhost:8080で実際に画面を表示したりする。そのとき、想定していたhtmlファイルに遷移せずに謎のログインページに飛ばされた。

調べてみると、どうやらSpringSecurityを使用する場合に出てくるものみたい。

対応策

デフォルト設定であればユーザー名は`"user"`、SpringBoot起動時にコンソールに表示されるパスワードを入力してあげるとログインして、目的のページにたどり着くみたい。

※もしSpringSecurityを使わないのであれば、依存関係を削除すればOK!

参考:Spring Boot project shows the login page

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

【Android Studio】 SQLiteを使いやすくするクラス テーブルの作成・削除 

概要

Android Studioには、データベースを用いたアプリケーションを作りやすくするために「SQLiteOpenHelper」クラスや「SQLiteDatabase」クラスなどのクラスが用意されています。
これらのクラスはとても便利で使いやすいのですが、

・テーブルを作る際に既に同じ名前のテーブルが存在しないかチェックする必要がある。
・SQLをコード中に直接書く必要がある。
・SQLはStringオブジェクトとして書く必要があり、間違ってコーディングしたときに気づきにくい。
・Stringオブジェクトとして書いたSQLが邪魔でちょっと見ずらい。

という点で不便だなと思うことがありました。
中でも、私はもともとwebアプリケーションを作っていたので生のSQLがコードにあると不安になってしまうというきらいがあります。
また、何がしているのか直感的に分かるコードが好きでもあります。
ということで今回は、関数チックにSQLを使えてメインのプログラムを見たときに何をしているのか分かりやすいものであることを目標にして「SQLiteDatabase」クラスをサポートするクラスを作っていこうと思います。

ソースコード

「controlTable」クラス

controlTable.java
package com.example;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class controlTable implements SQLiteSupporter {
    public void createTable(SQLiteDatabase dbObject, String tableName, String[][] list) {
        if (!getTableExist(dbObject,tableName)) {
            StringBuilder createTable = new StringBuilder("CREATE TABLE ");
            for (String[] str :list) {
                if (str == list[0]) {
                    String s = tableName + "(" + str[0] + " " + str[1] + " PRIMARY KEY";
                    createTable.append(s);
                } else {
                    String s = ", " + str[0] + " " + str[1];
                    createTable.append(s);
                }
            }
            createTable.append(")");
            dbObject.execSQL(createTable.toString());
        }
    }

    public void dropTable(SQLiteDatabase dbObject,String tableName) {
        if (getTableExist(dbObject,tableName)) {
            String dropTable = String.format("DROP TABLE IF EXISTS '%s'",tableName);
            dbObject.execSQL(dropTable);
        }
    }

    private boolean getTableExist(SQLiteDatabase dbObject, String tableName){
        String query = String.format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%s';", tableName);
        Cursor c = dbObject.rawQuery(query, null);
        c.moveToFirst();
        String result = c.getString(0);
        return !result.equals("0");
    }
}

「SQLiteSupporter」というインターフェイスを継承していますが、メインプログラムが読みやすくなるためと後で機能を変えやすくするためですので継承させなくても構いません。

今回はテーブルの作成と削除だけですので、非常にシンプルですね。
テーブルの作成はcreateTableメゾットで、削除はdropTableメゾットで行います。テーブルの有無はgetTableExistメゾットで行います。
これらの使い方は後ほど具体例を交えて説明するとして、大まかにソースコードの中身をいうと基本的には受け取った引数をもとにSQLを組み立ててそれを実行するといった感じですね。これは後々作るであろう他のメゾットでも変わらないと思います。

「controlTable」クラスが継承しているインターフェイス

SQLiteSupporter.java
package com.example;

import android.database.sqlite.SQLiteDatabase;

public interface SQLiteSupporter {
public void createTable (SQLiteDatabase dbObject, String tableName, String[][] list) ;
public void delateTable (SQLiteDatabase dbObject,String tableName);
}

これも特に説明するところはないですね。ただ、引数を決め過ぎたかなーと思ったのでオーバーロードしてテーブルを全て消す機能などを追加してもいいかなと個人的には思いました。

各メゾットの使い方

createTableメゾット

createTableには引数が三つあります。
一つ目は、「SQLiteDatabase」クラスのインスタンスです。注意点はopenOrCreateDatabaseメゾットを使った後に入れるということです。

SQLiteDatabase dbObject;
String dbName ;

/////////////////////////////////////////////////////////////////////////////////////
dbName = "data/data/" + getActivity() + "/myDatabase1.db";
dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null);

私の場合はフラグメント内で使いたかったのでgetActivityメゾットを使ってデータベースの場所と取得しました。データベースの名前もデフォルトのままですのでmyDatabase1.dbで取得できています。
参考までにコードを載せてはいますが、ここに関しては使う場所などによって取得方法に違いがでると思います。

二つ目の引数の名前はテーブル名の名前です。Stringオブジェクトとして好きな名前を入れて下さい。

string name = "table";

三つ目の引数はテーブルの項目です。下記のようなStringオブジェクトの配列で入れて下さい。一番最初の項目が主キーになります。
{項目名,項目のデータ形}です。

String[][] data = {
                    {"id", "INTEGER"},
                    {"type", "STRING"},
                    {"int", "INTEGER"},
                    {"date", "STRING"},
                    {"category", "STRING"},
                    {"tag", "STRING"}
                  };

createTableメゾットにこれらの引数を入れるとテーブルを作ることが出来ます。

SQLiteDatabase dbObject;
String dbName ;


dbName = "data/data/" + getActivity() + "/myDatabase1.db";
dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null);
string name = "table";
String[][] data = {
                    {"id", "INTEGER"},
                    {"type", "STRING"},
                    {"int", "INTEGER"},
                    {"date", "STRING"},
                    {"category", "STRING"},
                    {"tag", "STRING"}
                  };
SQLiteSupporter db = new controlTable();
db.createTable(dbObject,name, data);

delateTableメゾット

createメゾットとだいたい一緒です。SQLiteDatabaseクラスのインスタンスとテーブルの名前を入れて下さい。

SQLiteDatabase dbObject;
String dbName ;


dbName = "data/data/" + getActivity() + "/myDatabase1.db";
dbObject = SQLiteDatabase.openOrCreateDatabase(dbName,null);
string name = "table";

SQLiteSupporter db = new controlTable();
db.dropTable(dbObject,name);

まとめ

テーブルを作るのが一つだけでいいという場合はSQLを直接書いた方がいいと思います。また、簡単な構造で必要なコード数が少ない場合もSQLを直接書いた方が余計なファイルを増やさずに済むのでいいと思います。
ただ、ボタン操作と関連付けたり、頻繁にテーブル操作を行う必要があったりする場合などはコードが煩雑になりやすいので今回のようにしてみてもいいのではないかと思います。
あとは、SQLはメゾットが組み立ててくれるのでテーブル名を変更したい場合や、項目の数や名前を変えたい場合はかなり楽に変えることができるので変更にも強くなります。実際、試しにSQLを直接書いたコードと今回のコードを作ってみ比べてみたのですが、目に見えて効果を感じることが出来ました。

ただ、createTableメゾット本体は外部キーには対応できていないので拡張の余地が残っているなと思います。
また、今回のような簡単なテーブル操作の場合だと可読性や保守性の向上という強みは生かされにくいので他の操作にも対応したものを作っていこうかなと思います。

拙いところや不具合等がありましたらコメント欄にてご指摘・ご指導のほどよろしくお願いします。では、失礼します。

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