環境
- Windows 11 Pro, 24H2, 26100.3476
- Windows Subsystem for Linux (WSL2), Ubuntu 24.04.2 (LTS), 5.15.167.4-microsoft-standard-WSL2
- Java 21 (LTS) - Visual Studio Codeの拡張機能用
- Java 17 (LTS) - Mavenプロジェクト用
- Apache Maven 3.9.9
- Visual Studio Code Remote Development Extension Pack - Localにインストール
- Visual Studio Code Extension Pack for Java - LocalとRemoteの両方にインストール
全体図
/ +-home | +-mizuki | +-workspace | +-java17 (ローカルリポジトリのルート) | +-.git | | | +-java17-split-list (プロジェクト) | +-.mvn | | |-jvm.config | | |-maven.config | | | +-src | | +-main | | | +-java | | | +-amnesia | | | +-app | | | | |-App.java (メインクラス) | | | | | | | +-util | | | |-Util.java | | | | | +-test | | +-java | | +-amnesia | | +-app | | | |-AppTest.java | | | | | +-util | | |-UtilTest.java | | | +-target | | |-java17-split-list-1.0-SNAPSHOT.jar | | | |-pom.xml | |-.gitignore | +-opt +-apache-maven-3.9.9 | +-bin | |-mvn | +-java +-jdk-17.0.14+7 | +-bin | |-java | +-jdk-21.0.6+7 +-bin |-java
GitHubのリポジトリ
1. Mavenプロジェクトを作成する
環境変数JAVA_HOMEにJava17を指定する。
$ export JAVA_HOME=/opt/java/jdk-17.0.14+7
Mavenプロジェクトを作成する。プロジェクト名はartifactIdで指定する。
$ cd /home/mizuki/workspace/java17 $ /opt/apache-maven-3.9.9/bin/mvn archetype:generate -DgroupId=amnesia.app -DartifactId=java17-split-list -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
実行結果
[INFO] Scanning for projects... [INFO] [INFO] ------------------< org.apache.maven:standalone-pom >------------------- [INFO] Building Maven Stub Project (No POM) 1 [INFO] --------------------------------[ pom ]--------------------------------- [INFO] [INFO] >>> archetype:3.3.1:generate (default-cli) > generate-sources @ standalone-pom >>> [INFO] [INFO] <<< archetype:3.3.1:generate (default-cli) < generate-sources @ standalone-pom <<< [INFO] [INFO] [INFO] --- archetype:3.3.1:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Batch mode [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.5 [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: amnesia.app [INFO] Parameter: artifactId, Value: java17-split-list [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: package, Value: amnesia.app [INFO] Parameter: packageInPathFormat, Value: amnesia/app [INFO] Parameter: junitVersion, Value: 5.11.0 [INFO] Parameter: package, Value: amnesia.app [INFO] Parameter: groupId, Value: amnesia.app [INFO] Parameter: artifactId, Value: java17-split-list [INFO] Parameter: javaCompilerVersion, Value: 17 [INFO] Parameter: version, Value: 1.0-SNAPSHOT [WARNING] Don't override file /home/mizuki/workspace/java17/java17-split-list/src/main/java/amnesia/app [WARNING] Don't override file /home/mizuki/workspace/java17/java17-split-list/src/test/java/amnesia/app [WARNING] CP Don't override file /home/mizuki/workspace/java17/java17-split-list/.mvn [INFO] Project created from Archetype in dir: /home/mizuki/workspace/java17/java17-split-list [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.837 s [INFO] Finished at: 2025-04-04T22:39:37+09:00 [INFO] ------------------------------------------------------------------------
参考情報
- Apache >> Maven >> Maven in 5 Minutes >> Creating a Project
2. Visual Studio CodeでMavenプロジェクトを開く
WSL2上のUbuntu側でMavenプロジェクトのディレクトリからVisual Studio Codeを起動する。
$ cd /home/mizuki/workspace/java17/java17-split-list $ code .
MavenプロジェクトをビルドしてJARファイルを作成する。
$ cd /home/mizuki/workspace/java17/java17-split-list $ /opt/apache-maven-3.9.9/bin/mvn clean package
実行結果。
[INFO] Building jar: /home/mizuki/workspace/java17/java17-split-list/target/java17-split-list-1.0-SNAPSHOT.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.087 s [INFO] Finished at: 2025-05-08T21:56:37+09:00 [INFO] ------------------------------------------------------------------------
作成したJARファイル内のメインクラスを実行する。
$ cd /home/mizuki/workspace/java17/java17-split-list/target $ $JAVA_HOME/bin/java -cp java17-split-list-1.0-SNAPSHOT.jar amnesia.app.App
実行結果。
Hello World!
3. リストを指定された件数ごとに分割する機能を実装する
amnesia.utilパッケージを追加する。
Visual Studio Code >> EXPLORER src/main/java/amnesia 右クリック New Java Package...
amnesia.util.Utilクラスを追加する。
Visual Studio Code >> EXPLORER src/main/java/amnesia/util 右クリック New Java File... Class...
amnesia.util.UtilクラスにsplitListメソッドを追加する。
package amnesia.util; import java.util.ArrayList; import java.util.List; public class Util { /** * リストを指定された件数ごとに分割する。 * * srcListが10,500件のリストの場合、 * countに2,000を指定すると2,000件のリストが5個、500件のリストが1個の合計6個のリストに分割される。 * * srcList[10500] * splitedList(0)=subList[2000] * splitedList(1)=subList[2000] * splitedList(2)=subList[2000] * splitedList(3)=subList[2000] * splitedList(4)=subList[2000] * splitedList(5)=subList[500] * * @param srcList 分割するリスト * @param count 何件ずつ分割するか * @return 指定された件数ごとに分割されたリスト */ public static <T> List<List<T>> splitList(List<T> srcList, int count) { if ((srcList == null) || srcList.isEmpty() || (count <= 0)) { return new ArrayList<>(); } List<List<T>> splitedList = new ArrayList<>(); int itemTotalIndex = 0; List<T> subList = new ArrayList<>(); while (itemTotalIndex < srcList.size()) { subList.add(srcList.get(itemTotalIndex++)); // 分割単位を満たしたsubListをここで回収する。 if (count <= subList.size()) { splitedList.add(subList); subList = new ArrayList<>(); } } // 分割単位を満たさない端数のsubListをここで回収する。 if (!subList.isEmpty()) { splitedList.add(subList); } return splitedList; } }
4. リストを指定された件数ごとに分割する機能のテストを実装する
テストにamnesia.utilパッケージを追加する。
Visual Studio Code >> EXPLORER src/test/java/amnesia 右クリック New Java Package...
テストにamnesia.util.UtilTestクラスを追加する。
Visual Studio Code >> EXPLORER src/test/java/amnesia/util 右クリック New Java File... Class...
amnesia.util.UtilTestクラスにテストケースを追加する。
package amnesia.util; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; public class UtilTest { /** * srcList=null */ @Test void test1() { List<List<String>> resultList = Util.splitList(null, 1); assertTrue(resultList.isEmpty()); } /** * srcList=empty */ @Test void test2() { List<List<String>> resultList = Util.splitList(new ArrayList<String>(), 1); assertTrue(resultList.isEmpty()); } /** * count<=0 */ @Test void test3() { List<String> srcList = new ArrayList<>(); srcList.add("1"); List<List<String>> resultList = Util.splitList(srcList, 0); assertTrue(resultList.isEmpty()); resultList = Util.splitList(srcList, -1); assertTrue(resultList.isEmpty()); } /** * srcList.size()=count */ @Test void test4() { for (int count = 1; count <= 10; count++) { List<Integer> srcList = new ArrayList<>(); for (int k = 0; k < count; k++) { srcList.add(k); } List<List<Integer>> resultList = Util.splitList(srcList, count); assertTrue(resultList.size() == 1); } } /** * 0 < count <= srcList.size * srcList.size < count */ @Test void test5() { List<Integer> srcList = new ArrayList<>(); for (int k = 0; k < 100; k++) { srcList.add(k); } for (int count = 1; count <= 200; count++) { List<List<Integer>> resultList = Util.splitList(srcList, count); System.out.println("srcList.size[" + srcList.size() + "]count[" + count + "]resultList.size[" + resultList.size() + "]"); int subListCount = srcList.size() / count; int mod = srcList.size() % count; if (mod == 0) { assertTrue(resultList.size() == subListCount); } else { assertTrue(resultList.size() == (subListCount + 1)); } } } }
5. メインクラスにリストを指定された件数ごとに分割する機能の呼び出しを実装する
src/main/java/amnesia/app/App.java
package amnesia.app; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import amnesia.util.Util; /** * Hello world! */ public class App { public static void main(String[] args) { System.out.println("Hello World!"); List<String> srcList = new ArrayList<>(Arrays.asList(new String[10500])); int count = 2000; List<List<String>> splitList = Util.splitList(srcList, count); for (int i = 0; i < splitList.size(); i++) { System.out.println(String.format("分割リスト[%d]=[%d]件", i, splitList.get(i).size())); } } }
6. メインクラスを実行して結果を確認する
MavenプロジェクトをビルドしてJARファイルを作成する。テストケースも実行される。
$ cd /home/mizuki/workspace/java17/java17-split-list $ /opt/apache-maven-3.9.9/bin/mvn clean package
実行結果。
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.018 s -- in amnesia.util.UtilTest [INFO] [INFO] Results: [INFO] [INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- jar:3.4.2:jar (default-jar) @ java17-split-list --- [INFO] Building jar: /home/mizuki/workspace/java17/java17-split-list/target/java17-split-list-1.0-SNAPSHOT.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.581 s [INFO] Finished at: 2025-05-24T21:37:36+09:00 [INFO] ------------------------------------------------------------------------
作成したJARファイル内のメインクラスを実行する。
$ cd /home/mizuki/workspace/java17/java17-split-list/target $ $JAVA_HOME/bin/java -cp java17-split-list-1.0-SNAPSHOT.jar amnesia.app.App
実行結果。
Hello World! 分割リスト[0]=[2000]件 分割リスト[1]=[2000]件 分割リスト[2]=[2000]件 分割リスト[3]=[2000]件 分割リスト[4]=[2000]件 分割リスト[5]=[500]件
7. プロジェクトをGitHubにアップロードする
始めにGitHub側のリモートリポジトリの構造を確認する。
github.com +-user_name +-java17 (リポジトリのルート) +-Java17Log4j (プロジェクト) +-java17-stringbuilder-substring (プロジェクト) +-java17-write-text-file (プロジェクト)
次に同じ構造になるようにローカル側のリポジトリを作成する。リポジトリのルートにあたる場所で作業する。
/home/mizuki/workspace/java17 (リポジトリのルート) +-java17-split-list (プロジェクト)
$ cd /home/mizuki/workspace/java17 $ git init
hint: Using 'master' as the name for the initial branch. This default branch name hint: is subject to change. To configure the initial branch name to use in all hint: of your new repositories, which will suppress this warning, call: hint: hint: git config --global init.defaultBranch <name> hint: hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and hint: 'development'. The just-created branch can be renamed via this command: hint: hint: git branch -m <name> Initialized empty Git repository in /home/mizuki/workspace/java17/.git/
GitHub側に合わせてブランチ名を"master"から"main"に変更する。
$ cd /home/mizuki/workspace/java17 $ git branch -m main
GitHubのリポジトリにアップロードしないファイルを指定する設定ファイルを追加する。プロジェクトのディレクトリの直下に.gitignoreファイルを追加する。
/home/mizuki/workspace/java17/java17-split-list/.gitignore
# Mavenの出力ディレクトリを除外する。 /target/
gitの設定にユーザー名とメールアドレスを設定する。"--global"オプションはUbuntuのユーザー単位の設定になる。
$ cd /home/mizuki/workspace/java17 $ git config --global user.name "Fukumura Mizuki" $ git config --global user.email mizuki@home
gitの設定を確認する。
$ cd /home/mizuki/workspace/java17 $ git config --list
user.name=Fukumura Mizuki user.email=mizuki@home
プロジェクトのファイルをgitで追跡する。Mavenの出力ディレクトリ(target)は.gitignoreファイルの設定により除外されている。
$ cd /home/mizuki/workspace/java17 $ git add java17-split-list
プロジェクトのファイルの状態を確認する。
$ cd /home/mizuki/workspace/java17 $ git status
On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: java17-split-list/.gitignore new file: java17-split-list/.mvn/jvm.config new file: java17-split-list/.mvn/maven.config new file: java17-split-list/pom.xml new file: java17-split-list/src/main/java/amnesia/app/App.java new file: java17-split-list/src/main/java/amnesia/util/Util.java new file: java17-split-list/src/test/java/amnesia/app/AppTest.java new file: java17-split-list/src/test/java/amnesia/util/UtilTest.java
プロジェクトのファイルをコミットする。
$ cd /home/mizuki/workspace/java17 $ git commit
GNU nanoが起動する。1行目にコミットメッセージ『initial commit』を入力する。"CTRL+O"で保存を指示して"Enter"でデフォルトのファイルにコミットメッセージを保存する。"CTRL+X"でGNU nanoを終了するとファイルがコミットされる。
[main (root-commit) 3bafc65] initial commit 8 files changed, 275 insertions(+) create mode 100644 java17-split-list/.gitignore create mode 100644 java17-split-list/.mvn/jvm.config create mode 100644 java17-split-list/.mvn/maven.config create mode 100644 java17-split-list/pom.xml create mode 100644 java17-split-list/src/main/java/amnesia/app/App.java create mode 100644 java17-split-list/src/main/java/amnesia/util/Util.java create mode 100644 java17-split-list/src/test/java/amnesia/app/AppTest.java create mode 100644 java17-split-list/src/test/java/amnesia/util/UtilTest.java
プロジェクトのファイルの状態を確認する。
$ cd /home/mizuki/workspace/java17 $ git status
On branch main nothing to commit, working tree clean
ローカル側のリポジトリにGitHub側のリモートリポジトリの参照を"github"という名前を付けて追加する。
$ git remote add github https://github.com/yvafdevnsk/java17 $ git remote -v
github https://github.com/yvafdevnsk/java17 (fetch) github https://github.com/yvafdevnsk/java17 (push)
GitHub側でpersonal access tokenを発行する。リポジトリに対する権限は"Contents"の"Read-and-write"にする。"Administrator"ではコミットできない。
Profile settings Developer settings Personal access tokens Fine-grained tokens
New fine-grained personal access token Toke name java17-contents-20250525 Expiration 30 days Repository access Only select repositories yvafdevnsk/java17 Permissions Repository permissions Contents Access: Read-and-write
ローカル側のリポジトリの履歴をGitHub側のリモートリポジトリに反映する。
$ cd /home/mizuki/workspace/java17 $ git push github main Username for 'https://github.com': <user_name> Password for 'https://yvafdevnsk@github.com': <personal_access_token>
To https://github.com/yvafdevnsk/java17 ! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/yvafdevnsk/java17' hint: Updates were rejected because the remote contains work that you do not hint: have locally. This is usually caused by another repository pushing to hint: the same ref. If you want to integrate the remote changes, use hint: 'git pull' before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
ローカル側のリポジトリにない履歴がGitHub側のリモートリポジトリにあるので、先にリモートリポジトリの履歴をローカルに持ってくる。
$ cd /home/mizuki/workspace/java17 $ git pull github main
remote: Enumerating objects: 78, done. remote: Counting objects: 100% (78/78), done. remote: Compressing objects: 100% (67/67), done. remote: Total 78 (delta 16), reused 40 (delta 1), pack-reused 0 (from 0) Unpacking objects: 100% (78/78), 23.47 KiB | 1.30 MiB/s, done. From https://github.com/yvafdevnsk/java17 * branch main -> FETCH_HEAD * [new branch] main -> github/main hint: You have divergent branches and need to specify how to reconcile them. hint: You can do so by running one of the following commands sometime before hint: your next pull: hint: hint: git config pull.rebase false # merge hint: git config pull.rebase true # rebase hint: git config pull.ff only # fast-forward only hint: hint: You can replace "git config" with "git config --global" to set a default hint: preference for all repositories. You can also pass --rebase, --no-rebase, hint: or --ff-only on the command line to override the configured default per hint: invocation. fatal: Need to specify how to reconcile divergent branches.
"git pull"コマンドに対して"merge"するか"rebase"するかを指定する必要がある。"rebase"を指定する。
$ cd /home/mizuki/workspace/java17 $ git pull --rebase github main
From https://github.com/yvafdevnsk/java17 * branch main -> FETCH_HEAD Successfully rebased and updated refs/heads/main.
もう一度、ローカル側のリポジトリの履歴をGitHub側のリモートリポジトリに反映する。
$ cd /home/mizuki/workspace/java17 $ git push github main Username for 'https://github.com': <user_name> Password for 'https://yvafdevnsk@github.com': <personal_access_token>
Enumerating objects: 23, done. Counting objects: 100% (23/23), done. Delta compression using up to 20 threads Compressing objects: 100% (13/13), done. Writing objects: 100% (22/22), 3.70 KiB | 3.70 MiB/s, done. Total 22 (delta 1), reused 0 (delta 0), pack-reused 0 remote: Resolving deltas: 100% (1/1), completed with 1 local object. To https://github.com/yvafdevnsk/java17 c40ee92..8b254eb main -> main
参考情報。
- 2.2 Git Basics - Recording Changes to the Repository - Ignoring Files
- 1.6 Getting Started - First-Time Git Setup - Your Identity
- 2.1 Git Basics - Getting a Git Repository - Getting a Git Repository
- 2.2 Git Basics - Recording Changes to the Repository - Tracking New Files
- 2.5 Git Basics - Working with Remotes - Adding Remote Repositories