diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 00000000000..d3643eda344
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+github:
+ description: "Apache Commons Lang"
+ homepage: https://commons.apache.org/lang/
+
+notifications:
+ commits: commits@commons.apache.org
+ issues: issues@commons.apache.org
+ pullrequests: issues@commons.apache.org
+ jira_options: link label
+ jobs: notifications@commons.apache.org
+ # commits_bot_dependabot: dependabot@commons.apache.org
+ issues_bot_dependabot: dependabot@commons.apache.org
+ pullrequests_bot_dependabot: dependabot@commons.apache.org
+ issues_bot_codecov-commenter: notifications@commons.apache.org
+ pullrequests_bot_codecov-commenter: notifications@commons.apache.org
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000000..715c926ab11
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Auto detect text files and perform LF normalization
+* text=auto
+
+*.java text diff=java
+*.html text diff=html
+*.css text
+*.js text
+*.sql text
diff --git a/.github/GH-ROBOTS.txt b/.github/GH-ROBOTS.txt
new file mode 100644
index 00000000000..64a88674fe4
--- /dev/null
+++ b/.github/GH-ROBOTS.txt
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Keeps on creating FUD PRs in test code
+# Does not follow Apache disclosure policies
+User-agent: JLLeitschuh/security-research
+Disallow: *
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..08d5e7de792
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: 2
+updates:
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "quarterly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "quarterly"
+
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 00000000000..9ff35c83e79
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,30 @@
+
+
+Thanks for your contribution to [Apache Commons](https://commons.apache.org/)! Your help is appreciated!
+
+Before you push a pull request, review this list:
+
+- [ ] Read the [contribution guidelines](CONTRIBUTING.md) for this project.
+- [ ] Read the [ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html) if you use Artificial Intelligence (AI).
+- [ ] I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute?
+- [ ] Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself.
+- [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice.
+- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
+- [ ] Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process.
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000000..c8f3dc198c4
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,86 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '33 9 * * 4'
+
+permissions:
+ contents: read
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ max-parallel: 20
+ fail-fast: false
+ matrix:
+ language: [ 'java', 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae #v5.0.5
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
new file mode 100644
index 00000000000..f0d8ca94e32
--- /dev/null
+++ b/.github/workflows/dependency-review.yml
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: 'Dependency Review'
+on: [pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ dependency-review:
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Checkout Repository'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ - name: 'Dependency Review PR'
+ uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 00000000000..e8d4ffb274e
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,59 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Java CI
+
+on:
+ push:
+ branches:
+ - 'master'
+ pull_request: {}
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+
+ runs-on: ${{ matrix.os }}
+ continue-on-error: ${{ matrix.experimental }}
+ strategy:
+ max-parallel: 20
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ java: [ 8, 11, 17, 21, 25 ]
+ experimental: [false]
+ include:
+ - java: 26-ea
+ experimental: true
+ os: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae #v5.0.5
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
+ with:
+ distribution: ${{ runner.os == 'macOS' && matrix.java == '8' && 'zulu' || 'temurin' }}
+ java-version: ${{ matrix.java }}
+ - name: Build with Maven
+ run: mvn --errors --show-version --batch-mode --no-transfer-progress -Ddoclint=all
diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml
new file mode 100644
index 00000000000..16e37f60506
--- /dev/null
+++ b/.github/workflows/scorecards-analysis.yml
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache license, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the license for the specific language governing permissions and
+# limitations under the license.
+
+name: "Scorecards supply-chain security"
+
+on:
+ branch_protection_rule:
+ schedule:
+ - cron: "30 1 * * 6" # Weekly on Saturdays
+ push:
+ branches: [ "master" ]
+
+permissions: read-all
+
+jobs:
+
+ analysis:
+
+ name: "Scorecards analysis"
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to the code-scanning dashboard.
+ security-events: write
+ actions: read
+ id-token: write # This is required for requesting the JWT
+ contents: read # This is required for actions/checkout
+
+ steps:
+
+ - name: "Checkout code"
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # 2.4.3
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # A read-only PAT token, which is sufficient for the action to function.
+ # The relevant discussion: https://github.com/ossf/scorecard-action/issues/188
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ # Publish the results for public repositories to enable scorecard badges.
+ # For more details: https://github.com/ossf/scorecard-action#publishing-results
+ publish_results: true
+
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
+ with:
+ sarif_file: results.sarif
diff --git a/.gitignore b/.gitignore
index 8f8fd6aafb1..8d85ed51cf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ target
maven-eclipse.xml
build.properties
site-content
+*~
+.mvn/
# IntelliJ IDEA files
.idea
@@ -15,4 +17,13 @@ site-content
.settings
.classpath
.project
-.externalToolBuilders
\ No newline at end of file
+.externalToolBuilders
+.checkstyle
+
+# jenv's version file
+.java-version
+/.DS_Store
+
+# NetBeans files
+nb-configuration.xml
+nbactions.xml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 5749fa8f3c4..00000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: java
-sudo: false
-
-jdk:
- - openjdk6
- - openjdk7
- - oraclejdk8
-
-after_success:
- - mvn clean cobertura:cobertura coveralls:report
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..b4342f33ca5
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,17 @@
+
+The Apache code of conduct page is [https://www.apache.org/foundation/policies/conduct.html](https://www.apache.org/foundation/policies/conduct.html).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bc418fc26d1..6566faba63f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,7 +6,7 @@
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
- | 1) Re-generate using: mvn commons:contributing-md |
+ | 1) Re-generate using: mvn commons-build:contributing-md |
| |
| 2) Set the following properties in the component's pom: |
| - commons.jira.id (required, alphabetic, upper case) |
@@ -41,57 +41,76 @@
Contributing to Apache Commons Lang
======================
-You have found a bug or you have an idea for a cool new feature? Contributing code is a great way to give something back to
-the open source community. Before you dig right into the code there are a few guidelines that we need contributors to
-follow so that we can have a chance of keeping on top of things.
+Have you found a bug or have an idea for a cool new feature? Contributing code is a great way to give something back to the open-source community.
+Before you dig right into the code, we need contributors to follow a few guidelines to have a chance of keeping on top of things.
Getting Started
---------------
+ Make sure you have a [JIRA account](https://issues.apache.org/jira/).
-+ Make sure you have a [GitHub account](https://github.com/signup/free).
-+ If you're planning to implement a new feature it makes sense to discuss you're changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons Lang's scope.
-+ Submit a ticket for your issue, assuming one does not already exist.
++ Make sure you have a [GitHub account](https://github.com/signup/free). This is not essential, but makes providing patches much easier.
++ If you're planning to implement a new feature it makes sense to discuss your changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons Lang's scope.
++ Submit a [Jira Ticket][jira] for your issue, assuming one does not already exist.
+ Clearly describe the issue including steps to reproduce when it is a bug.
+ Make sure you fill in the earliest version that you know has the issue.
-+ Fork the repository on GitHub.
++ Find the corresponding [repository on GitHub](https://github.com/apache/?query=commons-),
+[fork](https://help.github.com/articles/fork-a-repo/) and check out your forked repository. If you don't have a GitHub account, you can still clone the Commons repository.
Making Changes
--------------
-+ Create a topic branch from where you want to base your work (this is usually the master/trunk branch).
++ Create a _topic branch_ for your isolated work.
+ * Usually you should base your branch from the `master` branch.
+ * A good topic branch name can be the JIRA bug ID plus a keyword, e.g. `LANG-123-InputStream`.
+ * If you have submitted multiple JIRA issues, try to maintain separate branches and pull requests.
+ Make commits of logical units.
+ * Make sure your commit messages are meaningful and in the proper format. Your commit message should contain the key of the JIRA issue.
+ * For example, `[LANG-123] Close input stream sooner`
+ Respect the original code style:
- + Only use spaces for indentation.
- + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
- + Check for unnecessary whitespace with git diff --check before committing.
-+ Make sure your commit messages are in the proper format. Your commit message should contain the key of the JIRA issue.
-+ Make sure you have added the necessary tests for your changes.
-+ Run all the tests with `mvn clean verify` to assure nothing else was accidentally broken.
+ + Only use spaces for indentation; you can check for unnecessary whitespace with `git diff` before committing.
+ + Create minimal diffs - disable _On Save_ actions like _Reformat Source Code_ or _Organize Imports_. If you feel the source code should be reformatted create a separate PR for this change first.
++ Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible but is a best practice.
+Unit tests are typically in the `src/test/java` directory.
++ Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself.
++ Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
++ Each commit in the pull request should have a meaningful subject line and body. Note that commits might be squashed by a maintainer on merge.
+
Making Trivial Changes
----------------------
+The JIRA tickets are used to generate the changelog for the next release.
+
For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA.
-In this case, it is appropriate to start the first line of a commit with '(doc)' instead of a ticket number.
+In this case, it is appropriate to start the first line of a commit with '[doc]' or '[javadoc]' instead of a ticket number.
+
Submitting Changes
------------------
-+ Sign the [Contributor License Agreement][cla] if you haven't already.
++ Sign and submit the Apache [Contributor License Agreement][cla] if you haven't already.
+ * Note that small patches & typical bug fixes do not require a CLA as
+ clause 5 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0.html#contributions)
+ covers them.
+ Push your changes to a topic branch in your fork of the repository.
-+ Submit a pull request to the repository in the apache organization.
++ Submit a _Pull Request_ to the corresponding repository in the `apache` organization.
+ * Verify _Files Changed_ shows only your intended changes and does not
+ include additional files like `target/*.class`
+ Update your JIRA ticket and include a link to the pull request in the ticket.
+If you prefer to not use GitHub, then you can instead use
+`git format-patch` (or `svn diff`) and attach the patch file to the JIRA issue.
+
+
Additional Resources
--------------------
+ [Contributing patches](https://commons.apache.org/patches.html)
-+ [Apache Commons Lang JIRA project page](https://issues.apache.org/jira/browse/LANG)
++ [Apache Commons Lang JIRA project page][jira]
+ [Contributor License Agreement][cla]
+ [General GitHub documentation](https://help.github.com/)
-+ [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
++ [GitHub pull request documentation](https://help.github.com/articles/creating-a-pull-request/)
+ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons)
-+ #apachecommons IRC channel on freenode.org
[cla]:https://www.apache.org/licenses/#clas
+[jira]:https://issues.apache.org/jira/browse/LANG
diff --git a/LICENSE.txt b/LICENSE.txt
index d6456956733..ff9ad4530f5 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -193,7 +193,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/NOTICE.txt b/NOTICE.txt
index 592023af76b..246f39cc1d1 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,8 +1,5 @@
Apache Commons Lang
-Copyright 2001-2015 The Apache Software Foundation
+Copyright 2001-2026 The Apache Software Foundation
This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-This product includes software from the Spring Framework,
-under the Apache License 2.0 (see: StringUtils.containsWhitespace())
+The Apache Software Foundation (https://www.apache.org/).
diff --git a/README.md b/README.md
index 9c446c938e9..116f814b13d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
| commons-build-plugin/trunk/src/main/resources/commons-xdoc-templates |
+======================================================================+
| |
- | 1) Re-generate using: mvn commons:readme-md |
+ | 1) Re-generate using: mvn commons-build:readme-md |
| |
| 2) Set the following properties in the component's pom: |
| - commons.componentid (required, alphabetic, lower case) |
@@ -43,63 +43,85 @@
Apache Commons Lang
===================
-[](https://travis-ci.org/apache/commons-lang)
-[](https://coveralls.io/r/apache/commons-lang)
-[](https://maven-badges.herokuapp.com/maven-central/org.apache.commons/commons-lang3/)
-[](http://www.apache.org/licenses/LICENSE-2.0.html)
+[](https://github.com/apache/commons-lang/actions/workflows/maven.yml)
+[](https://search.maven.org/artifact/org.apache.commons/commons-lang3)
+[](https://javadoc.io/doc/org.apache.commons/commons-lang3/3.20.0)
+[](https://github.com/apache/commons-lang/actions/workflows/codeql-analysis.yml)
+[](https://api.securityscorecards.dev/projects/github.com/apache/commons-lang)
Apache Commons Lang, a package of Java utility classes for the
classes that are in java.lang's hierarchy, or are considered to be so
standard as to justify existence in java.lang.
+ The code is tested using the latest revision of the JDK for supported
+ LTS releases: 8, 11, 17, 21 and 25 currently.
+ See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+ Please ensure your build environment is up-to-date and kindly report any build issues.
+
Documentation
-------------
-More information can be found on the [homepage](https://commons.apache.org/proper/commons-lang).
-The [JavaDoc](https://commons.apache.org/proper/commons-lang/javadocs/api-release) can be browsed.
-Questions related to the usage of Apache Commons Lang should be posted to the [user mailing list][ml].
+More information can be found on the [Apache Commons Lang homepage](https://commons.apache.org/proper/commons-lang).
+The [Javadoc](https://commons.apache.org/proper/commons-lang/apidocs) can be browsed.
+Questions related to the usage of Apache Commons Lang should be posted to the [user mailing list](https://commons.apache.org/mail-lists.html).
-Where can I get the latest release?
------------------------------------
+Getting the latest release
+--------------------------
You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-lang/download_lang.cgi).
-Alternatively you can pull it from the central Maven repositories:
+Alternatively, you can pull it from the central Maven repositories:
```xml
org.apache.commonscommons-lang3
- 3.4
+ 3.20.0
```
+Building
+--------
+
+Building requires a Java JDK and [Apache Maven](https://maven.apache.org/).
+The required Java version is found in the `pom.xml` as the `maven.compiler.source` property.
+
+From a command shell, run `mvn` without arguments to invoke the default Maven goal to run all tests and checks.
+
Contributing
------------
-We accept PRs via github. The [developer mailing list][ml] is the main channel of communication for contributors.
+We accept Pull Requests via GitHub. The [developer mailing list](https://commons.apache.org/mail-lists.html) is the main channel of communication for contributors.
There are some guidelines which will make applying PRs easier for us:
+ No tabs! Please use spaces for indentation.
-+ Respect the code style.
++ Respect the existing code style for each file.
+ Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
-+ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn clean test```.
++ Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running `mvn`.
++ Before you push a PR, run `mvn` (without arguments). This runs the default goal which contains all build checks.
++ To see the code coverage report, regardless of coverage failures, run `mvn clean site -Dcommons.jacoco.haltOnFailure=false -Pjacoco`
If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas).
You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md).
License
-------
-Code is under the [Apache Licence v2](https://www.apache.org/licenses/LICENSE-2.0.txt).
+This code is licensed under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0).
+
+See the `NOTICE.txt` file for required notices and attributions.
-Donations
----------
-You like Apache Commons Lang? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development.
+Donating
+--------
+You like Apache Commons Lang? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support development.
Additional Resources
--------------------
+ [Apache Commons Homepage](https://commons.apache.org/)
-+ [Apache Bugtracker (JIRA)](https://issues.apache.org/jira/)
++ [Apache Issue Tracker (JIRA)](https://issues.apache.org/jira/browse/LANG)
++ [Apache Commons Slack Channel](https://the-asf.slack.com/archives/C60NVB8AD)
+ [Apache Commons Twitter Account](https://twitter.com/ApacheCommons)
-+ #apachecommons IRC channel on freenode.org
-[ml]:https://commons.apache.org/mail-lists.html
+Apache Commons Components
+-------------------------
+
+Please see the [list of components](https://commons.apache.org/components.html)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index dc3f520e123..c8b809c6cca 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -1,28 +1,2048 @@
- Apache Commons Lang
- Version 3.4
- Release Notes
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Apache Commons Lang 3.20.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.20.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17, 21 and 25 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add SystemProperties.getPath(String, Supplier). Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_25. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_26. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_25. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_26. Thanks to Gary Gregory.
+o Add MutablePair.ofNonNull(Map.Entry). Thanks to jack5505, Gary Gregory.
+o Add TimedSemaphore.builder(), Builder, and deprecate constructors. Thanks to Gary Gregory.
+o LANG-1504: Adding labels and history to split StopWatch #1473. Thanks to Edwin Delgado H, Gary Gregory.
+
+Fixed Bugs:
+o Optimize ObjectToStringComparator.compare() method #1449. Thanks to mayuming, Gary Gregory.
+o [javadoc] Improve StringUtils Javadoc #1450. Thanks to Marcono1234, Gary Gregory.
+o Fix internal inverted logic in private isEnum() method and correct its usage in getFirstEnum() #1454. Thanks to mayuming, Gary Gregory.
+o Use accessors in ToStringStyle so subclasses can effectively override them. Thanks to William Degrange, Gary Gregory, Rob Spoor.
+o `LocaleUtils.toLocale(String)` for a 2 letter country code now returns a value instead of throwing an `IllegalArgumentException`. Thanks to jack5505, Gary Gregory.
+o Fix typo in StringUtils.trunctate() IllegalArgumentException message and test assertion messages. Thanks to mayuming, Gary Gregory.
+o Fix test fixture in ReflectionDiffBuilderTest.testTransientFieldDifference() #1464. Thanks to mayuming, Gary Gregory.
+o LANG-1789: NullPointerException when generating NoSuchMethodException in MethodUtils. Thanks to Hylke van der Schaaf, Gary Gregory.
+o LANG-1786: Map deprecated TimeZone short IDs and avoid JRE WARNINGs to the console #1483. Thanks to Daniel Migowski, Gary Gregory, Lenny Primak.
+o LANG-1792: TypeUtils.toString() skips angle brackets for Class type. Thanks to Mykhailo Hryb, Gary Gregory.
+o Mention JDK 25 LTS as a tested version in the release notes #1485. Thanks to Sebastian Peters, Gary Gregory.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 88 to 92 #1472, #1484. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Apache Commons Lang 3.20.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.20.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add SystemProperties.getPath(String, Supplier). Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_25. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_26. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_25. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_26. Thanks to Gary Gregory.
+o Add MutablePair.ofNonNull(Map.Entry). Thanks to jack5505, Gary Gregory.
+o Add TimedSemaphore.builder(), Builder, and deprecate constructors. Thanks to Gary Gregory.
+o LANG-1504: Adding labels and history to split StopWatch #1473. Thanks to Edwin Delgado H, Gary Gregory.
+
+Fixed Bugs:
+o Optimize ObjectToStringComparator.compare() method #1449. Thanks to mayuming, Gary Gregory.
+o [javadoc] Improve StringUtils Javadoc #1450. Thanks to Marcono1234, Gary Gregory.
+o Fix internal inverted logic in private isEnum() method and correct its usage in getFirstEnum() #1454. Thanks to mayuming, Gary Gregory.
+o Use accessors in ToStringStyle so subclasses can effectively override them. Thanks to William Degrange, Gary Gregory, Rob Spoor.
+o `LocaleUtils.toLocale(String)` for a 2 letter country code now returns a value instead of throwing an `IllegalArgumentException`. Thanks to jack5505, Gary Gregory.
+o Fix typo in StringUtils.trunctate() IllegalArgumentException message and test assertion messages. Thanks to mayuming, Gary Gregory.
+o Fix test fixture in ReflectionDiffBuilderTest.testTransientFieldDifference() #1464. Thanks to mayuming, Gary Gregory.
+o LANG-1789: NullPointerException when generating NoSuchMethodException in MethodUtils. Thanks to Hylke van der Schaaf, Gary Gregory.
+o LANG-1786: Map deprecated TimeZone short IDs and avoid JRE WARNINGs to the console #1483. Thanks to Daniel Migowski, Gary Gregory, Lenny Primak.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 88 to 92 #1472, #1484. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.19.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.19.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add ArrayUtils.SOFT_MAX_ARRAY_LENGTH. Thanks to Gary Gregory.
+o Add SystemUtils.IS_OS_NETWARE. Thanks to Gary Gregory.
+o Add MethodUtils.getAccessibleMethod(Class, Method). Thanks to Gary Gregory.
+o Add documentation to site for CVE-2025-48924 ClassUtils.getClass(...) can throw a StackOverflowError on very long inputs. Thanks to Gary Gregory.
+o Add StringUtils.indexOfAny(CharSequence, int, char...). Thanks to Gary Gregory.
+o Add ConcurrentException.ConcurrentException(String). Thanks to Gary Gregory.
+o Add DateUtils.toLocalDateTime(Date[, TimeZone]) #1385. Thanks to Finger, Gary Gregory, Piotr P. Karwasz.
+o Add DateUtils.toOffsetDateTime(Date[, TimeZone]). Thanks to Gary Gregory.
+o Add DateUtils.toZonedDateTime(Date[, TimeZone]). Thanks to Gary Gregory.
+o Add ByteConsumer. Thanks to Gary Gregory.
+o Add ByteSupplier. Thanks to Gary Gregory.
+o Add FailableByteConsumer. Thanks to Gary Gregory.
+o Add FailableByteSupplier. Thanks to Gary Gregory.
+o LANG-1784: Add Functions methods for null-safe mapping and chaining #1435. Thanks to Rich Dougherty, Gary Gregory.
+o LANG-1784: Add Failable methods for null-safe mapping and chaining #1435. Thanks to Rich Dougherty, Gary Gregory.
+o Add DoubleRange.fit(double). Thanks to Gary Gregory.
+o Add IntegerRange.fit(int). Thanks to Gary Gregory.
+o Add LongRange.fit(long). Thanks to Gary Gregory.
+o Add DurationUtils.get(String, TemporalUnit, long). Thanks to Gary Gregory.
+o Add DurationUtils.getMillis(String, long). Thanks to Gary Gregory.
+o Add DurationUtils.getSeconds(String, long). Thanks to Gary Gregory.
+o Add SystemProperties.getBoolean(Class, String, boolean). Thanks to Gary Gregory.
+o Add SystemProperties.getInt(Class, String, int). Thanks to Gary Gregory.
+o Add SystemProperties.getLong(Class, String, long). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o LANG-1778: MethodUtils.getMatchingMethod() doesn't respect the hierarchy of methods #1414. Thanks to wuwu2000.
+o MethodUtils.getMethodObject(Class>, String, Class>...) now returns null instead of throwing a NullPointerException, as it does for other exception types. Thanks to Gary Gregory.
+o Reduce spurious failures in ArrayUtilsTest methods that test ArrayUtils.shuffle() methods. Thanks to Gary Gregory.
+o MethodUtils cannot find or invoke a public method on a public class implemented in its package-private superclass. Thanks to Gary Gregory.
+o AtomicSafeInitializer.get() can spin internally if the FailableSupplier given to AbstractConcurrentInitializer.AbstractBuilder.setInitializer(FailableSupplier) throws a RuntimeException. Thanks to Stanislav Fort, Gary Gregory.
+o LANG-1783: WordUtils.containsAllWords?() may throw PatternSyntaxException. Thanks to Arnout Engelen, Stanislav Fort, Gary Gregory.
+o LANG-1782: MethodUtils cannot find or invoke vararg methods without providing vararg types or values #1427. Thanks to Joe Ferner, Gary Gregory.
+o MethodUtils cannot find or invoke vararg methods of interface types. Thanks to Joe Ferner, Gary Gregory.
+o MethodUtils cannot find or invoke vararg methods when widening primitive types following the JLS 5.1.2. Widening Primitive Conversion. Thanks to Joe Ferner, Gary Gregory.
+o LANG-1597: Invocation fails because matching varargs method found but then discarded. Thanks to Richard Eckart de Castilho, Gary Gregory.
+o Don't check accessibility twice in MemberUtils.setAccessibleWorkaround(T). Thanks to Gary Gregory.
+o LANG-1774: Improve handling of ClassUtils.getShortCanonicalName() for invalid input #1437. Thanks to Zhongxin Yan, Madhur Lathi, Yudan Liu, Gary Gregory.
+o LANG-1720: Improve Javadocs for Conversion. Thanks to Sheung Chi Chan, Arthur Chan, Gary Gregory, Elliotte Rusty Harold.
+o Fix CalendarUtils.toLocalDate() Javadoc return type description #1440. Thanks to mayuming.
+o Fix the method name in Javadoc examples for CharUtils.isHex() #1444. Thanks to mayuming.
+o Deprecate NumberUtils.compare(byte, byte) in favor of Byte.compare(byte, byte). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(int, int) in favor of Integer.compare(int, int). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(long, long) in favor of Long.compare(long, long). Thanks to Gary Gregory.
+o Deprecate NumberUtils.compare(short, short) in favor of Short.compare(short, short). Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.AWT_TOOLKIT. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_FONTS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_GRAPHICSENV. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_HEADLESS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_AWT_PRINTERJOB. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_COMPILER. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_ENDORSED_DIRS. Thanks to Gary Gregory.
+o Deprecate obsolete system property constant SystemProperties.JAVA_EXT_DIRS. Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getAwtToolkit() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtFonts() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtGraphicsenv() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtHeadless() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaAwtPrinterjob() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaCompiler() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaEndorsedDirs() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemProperties.getJavaExtDirs() Thanks to Gary Gregory.
+o Deprecate method for obsolete system property constant SystemUtils.isJavaAwtHeadless() Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_FONTS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_GRAPHICSENV. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_HEADLESS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_AWT_PRINTERJOB. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_COMPILER. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_ENDORSED_DIRS. Thanks to Gary Gregory.
+o Deprecate constants for obsolete system property SystemUtils.JAVA_EXT_DIRS. Thanks to Gary Gregory.
+o [javadoc] General improvements. Thanks to Gary Gregory.
+o [javadoc] Fix thrown exception documentation for MethodUtils.getMethodObject(Class>, String, Class>...). Thanks to Gary Gregory.
+o [javadoc] Strings::equalsAny: CI doc string should show it's insensitive #1416. Thanks to Scott Parish.
+o [javadoc] General Javadoc improvements. Thanks to Gary Gregory.
+o LANG-1780: [javadoc] Fix Strings Javadoc #1419. Thanks to tza.
+o [javadoc] Fix typo in Javadoc of Strings instances #1406. Thanks to Sebastian Steiner.
+o [javadoc] Fix Javadocs in ClassUtils #1410. Thanks to Hassan A Hashim.
+o [javadoc] Fix @deprecated link for StringUtils#startsWithAny #1424. Thanks to mfg92.
+o Replace old feather logotype with new oak logotype. Thanks to Gary Gregory.
+
+Changes:
+o [test] Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0. Thanks to Gary Gregory.
+o Bump org.apache.commons:commons-parent from 85 to 88. Thanks to Gary Gregory.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.18.0 Release Notes
+----------------------------------------
+
+The Apache Commons Lang team is pleased to announce the release of Apache Commons Lang 3.18.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add Strings and refactor StringUtils. Thanks to Gary Gregory.
+o LANG-1747: Add StopWatch.run([Failable]Runnable) and get([Failable]Supplier). Thanks to Oliver B. Fischer, Gary Gregory.
+o Add JavaVersion.JAVA_23. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_24. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_23. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_24. Thanks to Gary Gregory.
+o Add IntegerRange.toIntStream(). Thanks to Gary Gregory.
+o Add LongRange.toLongStream(). Thanks to Gary Gregory.
+o Add IntStrams.of(int...). Thanks to Gary Gregory.
+o Add ArrayUtils.containsAny(int[], int...). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDate() #725. Thanks to asgh, Gary Gregory.
+o Add SystemUtils.IS_OS_MAC_OSX_SEQUOIA. Thanks to Gary Gregory.
+o Add BasicThreadFactory.builder() and deprecate BasicThreadFactory.Builder(). Thanks to Gary Gregory.
+o Add BasicThreadFactory.daemon(). Thanks to Gary Gregory.
+o Add ArrayUtils.startsWith. Thanks to Gary Gregory.
+o Add Predicates. Thanks to Gary Gregory.
+o Add RegExUtils methods typed to CharSequence input and deprecate old versions typed to String. Thanks to Gary Gregory.
+o Add IterableStringTokenizer. Thanks to Gary Gregory.
+o Add FailableIntToFloatFunction. Thanks to Gary Gregory.
+o Add Validate.isTrue(boolean, Supplier). Thanks to Gary Gregory.
+o Add EnumUtils.getFirstEnum(Class, int, ToIntFunction, E). Thanks to Gary Gregory.
+o Add FailableToBooleanFunction. Thanks to Gary Gregory.
+o Add the @FunctionalInterface annotation to org.apache.commons.lang3.concurrent.Computable. Thanks to Gary Gregory.
+o Add SystemUtils.getJavaIoTmpDirPath(). Thanks to Gary Gregory.
+o Add SystemUtils.getJavaHomePath(). Thanks to Gary Gregory.
+o Add SystemUtils.getUserDirPath(). Thanks to Gary Gregory.
+o Add SystemUtils.getUserHomePath(). Thanks to Gary Gregory.
+o Add ArrayFill.fill(T[], FailableIntFunction)). Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_DEBUG. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_CONF. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_KDC. Thanks to Gary Gregory.
+o Add SystemProperties.JAVA_SECURITY_KERBEROS_REAL. Thanks to Gary Gregory.
+o Add ArrayFill.fill(boolean[], boolean) #1386. Thanks to kommalapatiraviteja.
+o Add ObjectUtils.getIfNull(Object, Object) and deprecate defaultIfNull(Object, Object). Thanks to Pankraz76, Gary Gregory.
+o org.apache.commons.lang3.mutable.Mutable now extends Supplier. Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.CharUtils.isHex(char). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.CharUtils.isOctal(char). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.reentrantLockVisitor(Object). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.create(Object, ReentrantLock). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.concurrent.locks.LockingVisitors.ReentrantLockVisitor. Thanks to Gary Gregory.
+o Add builders for LockingVisitors implementations. Thanks to Gary Gregory.
+o Add EnumSet.stream(Class). Thanks to Gary Gregory.
+o Add org.apache.commons.lang3.SystemProperties.isPropertySet(String). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Fix flaky FileUtilsWaitForTest.testWaitForNegativeDuration(). Thanks to Gary Gregory.
+o Pick up exec-maven-plugin version from parent POM. Thanks to Gary Gregory.
+o Speed up and sanitize StopWatchTest. Thanks to Gary Gregory.
+o Fix handling of non-ASCII letters and numbers in RandomStringUtils #1273. Thanks to Fabrice Benhamouda.
+o Rewrite ClassUtils.getClass(...) without recursion to avoid StackOverflowError on very long inputs.
+ OSS-Fuzz Issue 42522972: apache-commons-text:StringSubstitutorInterpolatorFuzzer: Security exception in org.apache.commons.lang3.ClassUtils.getClass. Thanks to OSS-Fuzz, Gary Gregory.
+o Remove trailing whitespace in StopWatch exception messages. Thanks to Gary Gregory.
+o LANG-1754: Use getAllSuperclassesAndInterfaces() in getMatchingMethod() #1289. Thanks to vhbcm.
+o Add details to the ArrayFill Javadoc. Thanks to Gary Gregory.
+o Add details to the ArraySorter Javadoc. Thanks to Gary Gregory.
+o Fix broken URL to project location in Maven Central #1296. Thanks to Capt. Cutlass.
+o LANG-1753: StringUtils.replaceEachRepeatedly regression in 3.11+ #1297. Thanks to Capt. Cutlass.
+o Use simplified JUnit assertion methods #1298. Thanks to Capt. Cutlass.
+o LANG-1682: Javadoc and test: Use Strings.CI.startsWithAny method instead #1299. Thanks to Capt. Cutlass.
+o Fix NullPointerException in FastDateParser.TimeZoneStrategy.setCalendar(FastDateParser, Calendar, String) on Java 23. Thanks to Gary Gregory.
+o LANG-1757: Fix NullPointerException in MethodUtils.getMatchingAccessibleMethod((Class, String, Class...)). Thanks to Gary Gregory.
+o LANG-1698: Fix StackOverflowError in TypeUtils.typeVariableToString(TypeVariable), TypeUtils.toString(Type) on Java 17 and up. Thanks to Jan Arne Sparka, Gary Gregory.
+o LANG-1511: SystemUtils is missing important documentation. Thanks to david cogen, Gary Gregory, Bruno P. Kinoshita.
+o Make Failable.run(FailableRunnable) null-safe. Thanks to Gary Gregory.
+o Make Failable.accept(*) null-safe. Thanks to Gary Gregory.
+o Improve container detection by mimicking systemd #1323. Thanks to maxxedev, Piotr P. Karwasz, Gary Gregory.
+o Make LangCollectors.collect(...) null-safe. Thanks to Gary Gregory.
+o Make LangCollectors.collect(...) null-safe. Thanks to Gary Gregory.
+o Fix names of UTF-16 surrogate character test fixture constants, see also #1326. Thanks to IBue, Gary Gregory.
+o Moditect plugin generates split package warnings. Thanks to Gary Gregory.
+o LocaleUtils.availableLocaleSet() uses predictable iteration order. Thanks to Gary Gregory.
+o LANG-1759: SerializationUtils.clone(Object) throws ClassCastException when called with a Serializable lambda. Thanks to Maxim Butov, Gary Gregory.
+o LANG-1759: [StringUtils::indexOfAnyBut] redesign due to inconsistent/faulty behavior regarding UTF-16 surrogates #1327. Thanks to IBue, Gary Gregory, Piotr P. Karwasz.
+o Undeprecate ObjectUtils.toString(Object). Thanks to Gary Gregory.
+o Fix Spotbugs [ERROR] Medium: The field org.apache.commons.lang3.builder.DiffBuilder$SDiff.leftSupplier is transient but isn't set by deserialization [org.apache.commons.lang3.builder.DiffBuilder$SDiff] In DiffBuilder.java SE_TRANSIENT_FIELD_NOT_RESTORED. Thanks to Gary Gregory.
+o Fix Spotbugs [ERROR] Medium: The field org.apache.commons.lang3.builder.DiffBuilder$SDiff.rightSupplier is transient but isn't set by deserialization [org.apache.commons.lang3.builder.DiffBuilder$SDiff] In DiffBuilder.java SE_TRANSIENT_FIELD_NOT_RESTORED. Thanks to Gary Gregory.
+o LANG-1762: StopWatch methods should not delegate to deprecated methods. Thanks to Alonso Gonzalez, Gary Gregory.
+o Don't call TypeUtils.toString(Type) on every array item in TypeUtils.parameterize[WithOwner](Type, Class, Map, Type>) unless required. Thanks to Gary Gregory.
+o Remove -nouses directive from maven-bundle-plugin. OSGi package imports now state 'uses' definitions for package imports, this doesn't affect JPMS (from org.apache.commons:commons-parent:80). Thanks to Gary Gregory.
+o Instead of throwing a NullPointerException, ArrayUtils.toStringArray(Object[]) should return "null" for null elements like ArrayUtils.toStringArray(Object[], String) returns its valueForNullElements. Thanks to Gary Gregory.
+o LANG-1764: Deprecate NumericEntityUnescaper.OPTION in favor of Apache Commons Text. Thanks to Gary Gregory.
+o Several hash collisions in Fraction class. Thanks to Gary Gregory.
+o LANG-1768: MutableLong and friends should provide better parsing exceptions Javadocs. Thanks to Wang Hailong, Gary Gregory.
+o Reimplement StringUtils.toCodePoints(CharSequence) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o Reimplement StringUtils.capitalize(String) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o Reimplement StringUtils.uncapitalize(String) to use java.lang.CharSequence.codePoints(). Thanks to Gary Gregory.
+o org.apache.commons.lang3.ClassUtils.getCanonicalName(String) now throws an IllegalArgumentException for array dimensions greater than 255. Thanks to Gary Gregory.
+o Fix Javadoc typo and improve clarity in defaultIfBlank method #1376. Thanks to Sridhar Balijepalli, Piotr P. Karwasz.
+o LANG-1773: Apache Commons Lang no longer builds on Android #1381. Thanks to amonn McManus, Gary Gregory.
+o LANG-1772: Restrict size of cache to prevent overflow errors #1379. Thanks to James Winters, Piotr P. Karwasz, Gary Gregory.
+o LANG-1772: Reimplement org.apache.commons.lang3.ClassUtils.hierarchy(Class, Interfaces) using an AtomicReference. Thanks to Gary Gregory.
+o Fix Javadoc code examples in DiffBuilder and ReflectionDiffBuilder #1400. Thanks to Ken Dombeck.
+o Fix generics in org.apache.commons.lang3.stream.Streams.toArray(Class) signature. Thanks to Gary Gregory.
+o LANG-1727: EventListenerSupport doesn't document ordering of events. Thanks to Elliotte Rusty Harold, Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.IS_OS_ANDROID. Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast(JavaVersion). Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.SystemUtils.isJavaVersionAtMost(JavaVersion). Thanks to Gary Gregory.
+o Return the default enum if a SecurityException is caught in getEnumSystemProperty(). Thanks to Gary Gregory.
+o Fix edge-case NullPointerException in org.apache.commons.lang3.EnumUtils.getEnum(Class, String, E). Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getFirstEnumIgnoreCase(Class, String, Function, E) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getEnumIgnoreCase(Class, String, E) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o org.apache.commons.lang3.EnumUtils.getEnumIgnoreCase(Class, String) now returns the given default enum on null enumClass input. Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.equalTo(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.greaterThan(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.greaterThanOrEqualTo(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.lessThan(A). Thanks to Gary Gregory.
+o Fix NullPointerException in org.apache.commons.lang3.compare.ComparableUtils.ComparableCheckBuilder.lessThanOrEqualTo(A). Thanks to Gary Gregory.
+o LANG-1776: Use GitHub URL in POM for improved automation support.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 73 to 85 #1267, #1277, #1283, #1288, #1302, #1377. Thanks to Gary Gregory, Dependabot.
+o [site] Bump org.codehaus.mojo:taglist-maven-plugin from 3.1.0 to 3.2.1 #1300. Thanks to Gary Gregory, Dependabot.
+o [test] Bump org.easymock:easymock from 5.4.0 to 5.6.0 #1317, #1387. Thanks to Gary Gregory, Dependabot.
+o [test] Bump org.apache.commons:commons-text from 1.12.0 to 1.13.1 #1336. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.17.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.17.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o RandomUtils.secure() now uses SecureRandom() instead of SecureRandom.getInstanceStrong(). Thanks to Gary Gregory.
+o RandomStringUtils.secure() now uses SecureRandom() instead of SecureRandom.getInstanceStrong(). Thanks to Gary Gregory.
+o Remove unused exception from deprecated StringUtils.toString(byte[], String). Thanks to Gary Gregory.
+o Make RandomUtils.insecure() public. Thanks to Gary Gregory.
+o Add RandomUtils.secureStrong(). Thanks to Gary Gregory.
+o Add RandomStringUtils.secureStrong(). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toLocalDateTime(). Thanks to Gary Gregory.
+o Add CalendarUtils.toZonedDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toZonedDateTime(). Thanks to Gary Gregory.
+o Add CalendarUtils.toOffsetDateTime(Calendar). Thanks to Gary Gregory.
+o Add CalendarUtils.toOffsetDateTime(). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o LANG-1760: Using RandomStringUtils.insecure() still leads to using the secure() random. Thanks to Marco Hoek, Gary Gregory.
+o Deprecate static RandomUtils.next*() methods in favor or .secure() and .insecure() versions. Thanks to Gary Gregory.
+o Deprecate static RandomStringUtils.random*() methods in favor or .secure() and .insecure() versions. Thanks to Gary Gregory.
+
+Changes:
+o Bump org.hamcrest:hamcrest from 2.2 to 3.0 #1255. Thanks to Gary Gregory, Dependabot.
+o Bump org.easymock:easymock from 5.3.0 to 5.4.0 #1256. Thanks to Gary Gregory, Dependabot.
+o Bump org.codehaus.mojo:exec-maven-plugin from 3.3.0 to 3.4.1 #1262, #1264. Thanks to Gary Gregory, Dependabot.
+o Bump org.apache.commons:commons-parent from 72 to 73 #1265. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.16.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.16.0.
+
+Commons Lang is a set of utility functions and reusable components that should be useful in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, using those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+This is a feature and maintenance release. Java 8 or later is required.
+
+Changes in this version include:
+
+New features:
+o Add StopWatch.getSplitDuration() and deprecate getSplitTime(). Thanks to Gary Gregory.
+o Add StopWatch.getStartInstant() and deprecate getStartTime(). Thanks to Gary Gregory.
+o Add StopWatch.getStopInstant() and deprecate getStopTime(). Thanks to Gary Gregory.
+o Add StopWatch.getDuration() and deprecate getTime(). Thanks to Gary Gregory.
+o Add Javadoc links from StopWatch to DurationUtils #1249. Thanks to Oliver B. Fischer, Gary Gregory.
+o Add LangCollectors.collect(Collector, T...). Thanks to Gary Gregory.
+o Add RandomStringUtils.secure(). Thanks to Gary Gregory.
+o Add RandomStringUtils.insecure(). Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Reimplement StopWatch internals to use java.time. Thanks to Gary Gregory.
+o LANG-1745: RandomStringUtils.random() with a negative character index should throw IllegalArgumentException. Thanks to Wang Hailong, Gary Gregory.
+o LANG-1741: LocaleUtils.toLocale(String) cannot parse four segments. Thanks to Wang Hailong, Gary Gregory.
+o Use fewer intermediary strings in DefaultExceptionContext.getFormattedExceptionMessage(String). Thanks to Gary Gregory.
+o Fix Javadoc in StringUtils.splitPreserveAllTokens() #1251. Thanks to V�clav Haisman.
+o Deprecate ArraySort constructor for removal. Thanks to Gary Gregory.
+o Deprecate CharEncoding constructor for removal. Thanks to Gary Gregory.
+o Deprecate Conversion constructor for removal. Thanks to Gary Gregory.
+o Deprecate Conversion constructor for removal. Thanks to Gary Gregory.
+o Deprecate EntityArrays constructor for removal. Thanks to Gary Gregory.
+o Deprecate ObjectToStringComparator constructor for removal. Thanks to Gary Gregory.
+o Deprecate RuntimeEnvironment constructor for removal. Thanks to Gary Gregory.
+
+Changes:
+o Bump org.apache.commons:commons-parent from 71 to 72 #1253. Thanks to Gary Gregory, Dependabot.
+
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.15.0 Release Notes
+----------------------------------------
+
+The Apache Commons team is pleased to announce Apache Commons Lang Version 3.15.0.
+
+Commons Lang is a set of utility functions and reusable components that should be of use in any Java environment.
+
+Starting with Commons Lang 3.9, we target Java 8, making use of those features.
+
+For advice on upgrading from 2.x to 3.x, see:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+The code is tested using the latest revision of the JDK for supported
+LTS releases: 8, 11, 17 and 21 currently.
+See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml
+
+Please ensure your build environment is up-to-date and kindly report any build issues.
+
+New features and bug fixes (Java 8 or above).
+
+Changes in this version include:
+
+New features:
+o LANG-1724: Customize text pattern in DiffResult#toString(). Thanks to Gary Gregory, Dennis Baerten.
+o Add DiffBuilder.Builder. Thanks to Gary Gregory.
+o Add DiffBuilder.builder(). Thanks to Gary Gregory.
+o Add ReflectionDiffBuilder.Builder. Thanks to Gary Gregory.
+o Add ReflectionDiffBuilder.builder(). Thanks to Gary Gregory.
+o Add test in TypeUtilsTest #1151. Thanks to Elliotte Rusty Harold.
+o Add Streams.failableStream(T), non-varargs variant. Thanks to Gary Gregory.
+o Add Streams.nonNull(T), non-varargs variant. Thanks to Gary Gregory.
+o Add ArrayUtils.nullTo(T[], T[]). Thanks to Gary Gregory.
+o Add T ArrayUtils.arraycopy(T, int, T, int, int) fluent style. Thanks to Gary Gregory.
+o Add T ArrayUtils.arraycopy(T, int, int, int, Function) fluent style. Thanks to Gary Gregory.
+o Add SystemUtils.IS_JAVA_22. Thanks to Gary Gregory.
+o Add JavaVersion.JAVA_22. Thanks to Gary Gregory.
+o Add SystemProperties.getUserName(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties.getLineSeparator(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties.getJavaSpecificationVersion(Supplier). Thanks to Gary Gregory.
+o Add SystemProperties constants and methods for system properties as of Java 22. Thanks to Gary Gregory.
+o Add MethodUtils.getMethodObject(Class, String, Class...). Thanks to Gary Gregory.
+o LANG-1733: Add null-safe Consumers.accept() and Functions.apply() #1215. Thanks to Jongjin Bae, Gary Gregory.
+o Add SystemUtils.IS_OS_ANDROID. Thanks to Gary Gregory.
+o Add SystemUtils.IS_OS_MAC_OSX_SONOMA. Thanks to Gary Gregory.
+o Add RuntimeEnvironment.inContainer() #1241. Thanks to Gary Gregory.
+o Add AppendableJoiner and refactor string joining #1244. Thanks to Gary Gregory.
+
+Fixed Bugs:
+o Improve Javadoc in ExceptionUtils #1136. Thanks to Mikl�s Karak�, Gary Gregory.
+o Fixed two non-deterministic tests in EnumUtilsTest.java #1131. Thanks to Saiharshith Karuneegar Ramesh, Gary Gregory.
+o LANG-1721: Fix wrong number check that cause StringIndexOutOfBoundsException #1140. Thanks to Arthur Chan, Gary Gregory.
+o LANG-1722: Rethrow NegativeArraySizeException as SerializationException in SerializationUtils.deserialize(InputStream) #1141. Thanks to Arthur Chan.
+o LANG-1723: Throw NumberFormatException instead of IndexOutOfBoundsException in NumberUtils.getMantissa(String, int) #1145. Thanks to Arthur Chan, Gary Gregory.
+o Minor grammar fixes #1143. Thanks to Parano�d User.
+o LANG-1713: ArrayUtils will return null when adding two null arrays, but undocumented. Thanks to John Hendrikx, Gary Gregory.
+o Let parent POM figure out commons.spdx.version. Thanks to Gary Gregory.
+o LANG-1726: Undeprecate ExceptionUtils.rethrow(Throwable). Thanks to V�clav Haisman, Gary Gregory.
+o LANG-1702: Test the Conversion class #1155. Thanks to Elliotte Rusty Harold.
+o Address minor redundancies after code inspection #1148. Thanks to ParanoidUser, Elliotte Rusty Harold, Gary Gregory.
+o Allow EventListenerSupport to handle (and ignore) exception from listeners allowing invocation of all listeners #1167. Thanks to Gary Gregory.
+o Deprecate AnnotationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ArchUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ArrayUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate BooleanUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharSequenceUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharSetUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate CharUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassLoaderUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassPathUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ClassUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ConstructorUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DateFormatUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DateUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Diff.getType(). Thanks to Gary Gregory.
+o Deprecate DiffBuilder.DiffBuilder(T, T, ToStringStyle). Thanks to Gary Gregory.
+o Deprecate DiffBuilder.DiffBuilder(T, T, ToStringStyle, boolean). Thanks to Gary Gregory.
+o Deprecate DurationFormatUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate DurationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate EnumUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate EventUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate FieldUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate IEEE754rUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate InheritanceUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate IntStreams 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate LocaleUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate LockingVisitors 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate MemberUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate MethodUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate NumberUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ObjectUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate RandomStringUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate RandomUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ReflectionDiffBuilder.ReflectionDiffBuilder(T, T, ToStringStyle). Thanks to Gary Gregory.
+o Deprecate RegExUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate SerializationUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Streams 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate StringEscapeUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate StringUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate Suppliers 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate SystemProperties 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate ThreadUtils 0-argument constructor. Thanks to Gary Gregory.
+o Deprecate TypeUtils 0-argument constructor. Thanks to Gary Gregory.
+o Make ArrayFill null-safe. Thanks to Gary Gregory.
+o Make ArraySorter null-safe. Thanks to Gary Gregory.
+o Make ArrayUtils.removeAll() null-safe. Thanks to Gary Gregory.
+o Fix Java version in README.md #1170. Thanks to Philipp Trulson, Gary Gregory.
+o StringUtils.stripAccents() should handle ligatures, UTF32 math blocks, etc. #1201. Thanks to Stephan Peters, Gary Gregory, Bernd.
+o LANG-1524: TypeUtils.toString(Type) StackOverflowError for an inner class in the inner class parameterized enclosing class #657. Thanks to kijong.youn, Aakash Gupta, Gary Gregory.
+o Deprecate SystemUtils.getUserName(String) in favor of SystemProperties.getUserName(Supplier). Thanks to Gary Gregory.
+o Make LockVisitor.acceptReadLocked(FailableConsumer) null-safe. Thanks to Gary Gregory.
+o Make LockVisitor.applyWriteLocked(FailableConsumer) null-safe. Thanks to Gary Gregory.
+o Make ObjectUtils.getFirstNonNull(Supplier...) null-safe. Thanks to Gary Gregory.
+o Make SystemProperties.getLineSeparator(Supplier). Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle "\u0111" and "\u0110" (Vietnamese) #1216. Thanks to hunghhdev.
+o StringUtils.stripAccents(String) doesn't handle I with bar. Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle U with bar. Thanks to Gary Gregory.
+o StringUtils.stripAccents(String) doesn't handle T with stroke. Thanks to Gary Gregory.
+o LANG-1735: Fix Javadoc for FluentBitSet.setInclusive(int, int) #1222. Thanks to Tobias Kiecker.
+o Same Javadoc changes as [TEXT-234] #1223. Thanks to Tobias Kiecker.
+o Remove duplicate static data in SerializationUtils.ClassLoaderAwareObjectInputStream. Thanks to Gary Gregory.
+o Reimplement RandomUtils and RandomStringUtils on top of SecureRandom#getInstanceStrong() #1235. Thanks to Gary Gregory, Henri Yandell, Fabrice Benhamouda.
+o LANG-1657: DiffBuilder: Type constraint for method append(..., DiffResult) too strict #786. Thanks to Matthias Welz, Andrew Thomas, Gary Gregory.
+
+Changes:
+o Bump commons-parent from 64 to 71 #1194, #1233. Thanks to Dependabot, Gary Gregory.
+o Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.3.0 #1175, #1224. Thanks to Dependabot.
+o Bump org.apache.commons:commons-text from 1.11.0 to 1.12.0 #1200. Thanks to Dependabot.
+o Bump org.easymock:easymock from 5.2.0 to 5.3.0 #1232. Thanks to Dependabot.
+o Bump org.codehaus.mojo:taglist-maven-plugin from 3.0.0 to 3.1.0 #1242. Thanks to Dependabot.
+
+Removed:
+o Drop obsolete JDK 13 Maven profile #1142. Thanks to Parano�d User.
+
+Historical list of changes: https://commons.apache.org/proper/commons-lang/changes-report.html
+
+For complete information on Apache Commons Lang, including instructions on how to submit bug reports,
+patches, or suggestions for improvement, see the Apache Commons Lang website:
+
+https://commons.apache.org/proper/commons-lang/
+
+Download page: https://commons.apache.org/proper/commons-lang/download_lang.cgi
+
+Have fun!
+-Apache Commons Team
+
+-----------------------------------------------------------------------------
+
+Apache Commons Lang 3.14.0 Release Notes
+----------------------------------------
+
+This document contains the release notes for the 3.14.0 version of Apache Commons Lang.
+Commons Lang is a set of utility functions and reusable components that should be of use in any
+Java environment.
+
+Lang 3.9 and onwards now targets Java 8, making use of features that arrived with Java 8.
+
+For the advice on upgrading from 2.x to 3.x, see the following page:
+
+ https://commons.apache.org/lang/article3_0.html
+
+Apache Commons Lang, a package of Java utility classes for the
+classes that are in java.lang's hierarchy, or are considered to be so
+standard as to justify existence in java.lang.
+
+New features and bug fixes (Java 8 or above).
+
+Changes in this version include:
+
+New features:
+o Add Functions#function(Function). Thanks to Rob Spoor, Gary Gregory.
+o Add FailableFunction#function(FailableFunction). Thanks to Rob Spoor, Gary Gregory.
+o Add CalendarUtils.getInstance(). Thanks to Gary Gregory.
+o Add syntax for optional tokens to DurationFormatUtils #1062. Thanks to Dan Watson.
+o Add ArrayFill. Thanks to Gary Gregory.
+o Add FastDateParser.TimeZoneStrategy.TzInfo.toString(). Thanks to Gary Gregory.
+o Add LocaleUtils.isLanguageUndetermined(Locale). Thanks to Gary Gregory.
+o Add ObjectUtils.toString(Supplier
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final Object[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
There is no special handling for multi-dimensional arrays.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final long[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final int[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final short[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final char[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final byte[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final double[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final float[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps two elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- *
- *
Examples:
- *
- *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
- *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
- *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
- *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element to swap
- * @param offset2 the index of the second element to swap
- */
- public static void swap(final boolean[] array, int offset1, int offset2) {
- if (array == null || array.length == 0) {
- return;
- }
- swap(array, offset1, offset2, 1);
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final boolean[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- boolean aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
-
- public static void swap(final byte[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- byte aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final char[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- char aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final double[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- double aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final float[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- float aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
-
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final int[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- int aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final long[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- long aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final Object[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- Object aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- /**
- *
Swaps a series of elements in the given array.
- *
- *
This method does nothing for a {@code null} or empty input array or for overflow indices.
- * Negative indices are promoted to 0(zero).
- * If any of the sub-arrays to swap falls outside of the given array,
- * then the swap is stopped at the end of the array and as many as possible elements are swapped.
- *
- *
- *
- * @param array the array to swap, may be {@code null}
- * @param offset1 the index of the first element in the series to swap
- * @param offset2 the index of the second element in the series to swap
- * @param len the number of elements to swap starting with the given indices
- */
- public static void swap(final short[] array, int offset1, int offset2, int len) {
- if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) {
- return;
- }
- if (offset1 < 0) {
- offset1 = 0;
- }
- if (offset2 < 0) {
- offset2 = 0;
- }
- if (offset1 == offset2) {
- return;
- }
- len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
- for (int i = 0; i < len; i++, offset1++, offset2++) {
- short aux = array[offset1];
- array[offset1] = array[offset2];
- array[offset2] = aux;
- }
- }
-
- // Shift
- //-----------------------------------------------------------------------
- /**
- *
Shifts the order of the given array.
- *
- *
There is no special handling for multi-dimensional arrays.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- * @param offset how many position to the right to shift the array, if negative it will be shiftd to the left.
- */
- public static void shift(final Object[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final long[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final int[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final short[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final char[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final byte[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final double[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final float[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
Shifts the order of the given array.
- *
- *
This method does nothing for a {@code null} input array.
- *
- * @param array the array to shift, may be {@code null}
- */
- public static void shift(final boolean[] array, int offset) {
- if (array == null) {
- return;
- }
- shift(array, 0, array.length, offset);
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final boolean[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final byte[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final char[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final double[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final float[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final int[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- */
- public static void shift(final long[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- */
- public static void shift(final Object[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- /**
- *
- * Shifts the order of the given array in the given range.
- *
- *
- *
- * This method does nothing for a {@code null} input array.
- *
- *
- * @param array
- * the array to shift, may be {@code null}
- * @param startIndexInclusive
- * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
- * change.
- * @param endIndexExclusive
- * elements up to endIndex-1 are shiftd in the array. Undervalue (< start index) results in no
- * change. Overvalue (>array.length) is demoted to array length.
- * @since 3.2
- */
- public static void shift(final short[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
- if (array == null) {
- return;
- }
- if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
- return;
- }
- if (startIndexInclusive < 0) {
- startIndexInclusive = 0;
- }
- if (endIndexExclusive >= array.length) {
- endIndexExclusive = array.length;
- }
- int n = endIndexExclusive - startIndexInclusive;
- if (n <= 1) {
- return;
- }
- offset %= n;
- if (offset < 0) {
- offset += n;
- }
- // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
- // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
- while (n > 1 && offset > 0) {
- int n_offset = n - offset;
-
- if (offset > n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset);
- n = offset;
- offset -= n_offset;
- } else if (offset < n_offset) {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- startIndexInclusive += offset;
- n = n_offset;
- } else {
- swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset);
- break;
- }
- }
- }
-
- // IndexOf search
- // ----------------------------------------------------------------------
-
- // Object IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given object in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param objectToFind the object to find, may be {@code null}
- * @return the index of the object within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final Object[] array, final Object objectToFind) {
- return indexOf(array, objectToFind, 0);
- }
-
- /**
- *
Finds the index of the given object in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param objectToFind the object to find, may be {@code null}
- * @param startIndex the index to start searching at
- * @return the index of the object within the array starting at the index,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- if (objectToFind == null) {
- for (int i = startIndex; i < array.length; i++) {
- if (array[i] == null) {
- return i;
- }
- }
- } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
- for (int i = startIndex; i < array.length; i++) {
- if (objectToFind.equals(array[i])) {
- return i;
- }
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given object within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param objectToFind the object to find, may be {@code null}
- * @return the last index of the object within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final Object[] array, final Object objectToFind) {
- return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given object in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
- * the array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param objectToFind the object to find, may be {@code null}
- * @param startIndex the start index to travers backwards from
- * @return the last index of the object within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final Object[] array, final Object objectToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- if (objectToFind == null) {
- for (int i = startIndex; i >= 0; i--) {
- if (array[i] == null) {
- return i;
- }
- }
- } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
- for (int i = startIndex; i >= 0; i--) {
- if (objectToFind.equals(array[i])) {
- return i;
- }
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the object is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param objectToFind the object to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final Object[] array, final Object objectToFind) {
- return indexOf(array, objectToFind) != INDEX_NOT_FOUND;
- }
-
- // long IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final long[] array, final long valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final long[] array, final long valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final long[] array, final long valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final long[] array, final long valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final long[] array, final long valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // int IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final int[] array, final int valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final int[] array, final int valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final int[] array, final int valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final int[] array, final int valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final int[] array, final int valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // short IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final short[] array, final short valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final short[] array, final short valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final short[] array, final short valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final short[] array, final short valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final short[] array, final short valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // char IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- * @since 2.1
- */
- public static int indexOf(final char[] array, final char valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- * @since 2.1
- */
- public static int indexOf(final char[] array, final char valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- * @since 2.1
- */
- public static int lastIndexOf(final char[] array, final char valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- * @since 2.1
- */
- public static int lastIndexOf(final char[] array, final char valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- * @since 2.1
- */
- public static boolean contains(final char[] array, final char valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // byte IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final byte[] array, final byte valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final byte[] array, final byte valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final byte[] array, final byte valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final byte[] array, final byte valueToFind, int startIndex) {
- if (array == null) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final byte[] array, final byte valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // double IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final double[] array, final double valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value within a given tolerance in the array.
- * This method will return the index of the first value which falls between the region
- * defined by valueToFind - tolerance and valueToFind + tolerance.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param tolerance tolerance of the search
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final double[] array, final double valueToFind, final double tolerance) {
- return indexOf(array, valueToFind, 0, tolerance);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final double[] array, final double valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- * This method will return the index of the first value which falls between the region
- * defined by valueToFind - tolerance and valueToFind + tolerance.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @param tolerance tolerance of the search
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- final double min = valueToFind - tolerance;
- final double max = valueToFind + tolerance;
- for (int i = startIndex; i < array.length; i++) {
- if (array[i] >= min && array[i] <= max) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final double[] array, final double valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value within a given tolerance in the array.
- * This method will return the index of the last value which falls between the region
- * defined by valueToFind - tolerance and valueToFind + tolerance.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param tolerance tolerance of the search
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final double[] array, final double valueToFind, final double tolerance) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- * This method will return the index of the last value which falls between the region
- * defined by valueToFind - tolerance and valueToFind + tolerance.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @param tolerance search for value within plus/minus this amount
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- final double min = valueToFind - tolerance;
- final double max = valueToFind + tolerance;
- for (int i = startIndex; i >= 0; i--) {
- if (array[i] >= min && array[i] <= max) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final double[] array, final double valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if a value falling within the given tolerance is in the
- * given array. If the array contains a value within the inclusive range
- * defined by (value - tolerance) to (value + tolerance).
- *
- *
The method returns {@code false} if a {@code null} array
- * is passed in.
- *
- * @param array the array to search
- * @param valueToFind the value to find
- * @param tolerance the array contains the tolerance of the search
- * @return true if value falling within tolerance is in array
- */
- public static boolean contains(final double[] array, final double valueToFind, final double tolerance) {
- return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND;
- }
-
- // float IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final float[] array, final float valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final float[] array, final float valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final float[] array, final float valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
- * array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final float[] array, final float valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final float[] array, final float valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // boolean IndexOf
- //-----------------------------------------------------------------------
- /**
- *
Finds the index of the given value in the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int indexOf(final boolean[] array, final boolean valueToFind) {
- return indexOf(array, valueToFind, 0);
- }
-
- /**
- *
Finds the index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex is treated as zero. A startIndex larger than the array
- * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
- *
- * @param array the array to search through for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the index to start searching at
- * @return the index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null}
- * array input
- */
- public static int indexOf(final boolean[] array, final boolean valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- startIndex = 0;
- }
- for (int i = startIndex; i < array.length; i++) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Finds the last index of the given value within the array.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) if
- * {@code null} array input.
- *
- * @param array the array to travers backwords looking for the object, may be {@code null}
- * @param valueToFind the object to find
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final boolean[] array, final boolean valueToFind) {
- return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
- }
-
- /**
- *
Finds the last index of the given value in the array starting at the given index.
- *
- *
This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
- *
- *
A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
- * the array length will search from the end of the array.
- *
- * @param array the array to traverse for looking for the object, may be {@code null}
- * @param valueToFind the value to find
- * @param startIndex the start index to travers backwards from
- * @return the last index of the value within the array,
- * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
- */
- public static int lastIndexOf(final boolean[] array, final boolean valueToFind, int startIndex) {
- if (ArrayUtils.isEmpty(array)) {
- return INDEX_NOT_FOUND;
- }
- if (startIndex < 0) {
- return INDEX_NOT_FOUND;
- } else if (startIndex >= array.length) {
- startIndex = array.length - 1;
- }
- for (int i = startIndex; i >= 0; i--) {
- if (valueToFind == array[i]) {
- return i;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- /**
- *
Checks if the value is in the given array.
- *
- *
The method returns {@code false} if a {@code null} array is passed in.
- *
- * @param array the array to search through
- * @param valueToFind the value to find
- * @return {@code true} if the array contains the object
- */
- public static boolean contains(final boolean[] array, final boolean valueToFind) {
- return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
- }
-
- // Primitive/Object array converters
- // ----------------------------------------------------------------------
-
- // Character array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Characters to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Character} array, may be {@code null}
- * @return a {@code char} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static char[] toPrimitive(final Character[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_CHAR_ARRAY;
- }
- final char[] result = new char[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].charValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Character to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Character} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code char} array, {@code null} if null array input
- */
- public static char[] toPrimitive(final Character[] array, final char valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_CHAR_ARRAY;
- }
- final char[] result = new char[array.length];
- for (int i = 0; i < array.length; i++) {
- final Character b = array[i];
- result[i] = (b == null ? valueForNull : b.charValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive chars to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code char} array
- * @return a {@code Character} array, {@code null} if null array input
- */
- public static Character[] toObject(final char[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_CHARACTER_OBJECT_ARRAY;
- }
- final Character[] result = new Character[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Character.valueOf(array[i]);
- }
- return result;
- }
-
- // Long array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Longs to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Long} array, may be {@code null}
- * @return a {@code long} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static long[] toPrimitive(final Long[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_LONG_ARRAY;
- }
- final long[] result = new long[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].longValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Long to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Long} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code long} array, {@code null} if null array input
- */
- public static long[] toPrimitive(final Long[] array, final long valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_LONG_ARRAY;
- }
- final long[] result = new long[array.length];
- for (int i = 0; i < array.length; i++) {
- final Long b = array[i];
- result[i] = (b == null ? valueForNull : b.longValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive longs to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code long} array
- * @return a {@code Long} array, {@code null} if null array input
- */
- public static Long[] toObject(final long[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_LONG_OBJECT_ARRAY;
- }
- final Long[] result = new Long[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Long.valueOf(array[i]);
- }
- return result;
- }
-
- // Int array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Integers to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Integer} array, may be {@code null}
- * @return an {@code int} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static int[] toPrimitive(final Integer[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_INT_ARRAY;
- }
- final int[] result = new int[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].intValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Integer to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Integer} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return an {@code int} array, {@code null} if null array input
- */
- public static int[] toPrimitive(final Integer[] array, final int valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_INT_ARRAY;
- }
- final int[] result = new int[array.length];
- for (int i = 0; i < array.length; i++) {
- final Integer b = array[i];
- result[i] = (b == null ? valueForNull : b.intValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive ints to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array an {@code int} array
- * @return an {@code Integer} array, {@code null} if null array input
- */
- public static Integer[] toObject(final int[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_INTEGER_OBJECT_ARRAY;
- }
- final Integer[] result = new Integer[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Integer.valueOf(array[i]);
- }
- return result;
- }
-
- // Short array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Shorts to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Short} array, may be {@code null}
- * @return a {@code byte} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static short[] toPrimitive(final Short[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- final short[] result = new short[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].shortValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Short to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Short} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code byte} array, {@code null} if null array input
- */
- public static short[] toPrimitive(final Short[] array, final short valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- final short[] result = new short[array.length];
- for (int i = 0; i < array.length; i++) {
- final Short b = array[i];
- result[i] = (b == null ? valueForNull : b.shortValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive shorts to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code short} array
- * @return a {@code Short} array, {@code null} if null array input
- */
- public static Short[] toObject(final short[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_SHORT_OBJECT_ARRAY;
- }
- final Short[] result = new Short[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Short.valueOf(array[i]);
- }
- return result;
- }
-
- // Byte array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Bytes to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Byte} array, may be {@code null}
- * @return a {@code byte} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static byte[] toPrimitive(final Byte[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- final byte[] result = new byte[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].byteValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Bytes to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Byte} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code byte} array, {@code null} if null array input
- */
- public static byte[] toPrimitive(final Byte[] array, final byte valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- final byte[] result = new byte[array.length];
- for (int i = 0; i < array.length; i++) {
- final Byte b = array[i];
- result[i] = (b == null ? valueForNull : b.byteValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive bytes to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code byte} array
- * @return a {@code Byte} array, {@code null} if null array input
- */
- public static Byte[] toObject(final byte[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BYTE_OBJECT_ARRAY;
- }
- final Byte[] result = new Byte[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Byte.valueOf(array[i]);
- }
- return result;
- }
-
- // Double array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Doubles to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Double} array, may be {@code null}
- * @return a {@code double} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static double[] toPrimitive(final Double[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_DOUBLE_ARRAY;
- }
- final double[] result = new double[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].doubleValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Doubles to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Double} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code double} array, {@code null} if null array input
- */
- public static double[] toPrimitive(final Double[] array, final double valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_DOUBLE_ARRAY;
- }
- final double[] result = new double[array.length];
- for (int i = 0; i < array.length; i++) {
- final Double b = array[i];
- result[i] = (b == null ? valueForNull : b.doubleValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive doubles to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code double} array
- * @return a {@code Double} array, {@code null} if null array input
- */
- public static Double[] toObject(final double[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_DOUBLE_OBJECT_ARRAY;
- }
- final Double[] result = new Double[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Double.valueOf(array[i]);
- }
- return result;
- }
-
- // Float array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Floats to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Float} array, may be {@code null}
- * @return a {@code float} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static float[] toPrimitive(final Float[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_FLOAT_ARRAY;
- }
- final float[] result = new float[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].floatValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Floats to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Float} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code float} array, {@code null} if null array input
- */
- public static float[] toPrimitive(final Float[] array, final float valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_FLOAT_ARRAY;
- }
- final float[] result = new float[array.length];
- for (int i = 0; i < array.length; i++) {
- final Float b = array[i];
- result[i] = (b == null ? valueForNull : b.floatValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive floats to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code float} array
- * @return a {@code Float} array, {@code null} if null array input
- */
- public static Float[] toObject(final float[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_FLOAT_OBJECT_ARRAY;
- }
- final Float[] result = new Float[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = Float.valueOf(array[i]);
- }
- return result;
- }
-
- // Boolean array converters
- // ----------------------------------------------------------------------
- /**
- *
Converts an array of object Booleans to primitives.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Boolean} array, may be {@code null}
- * @return a {@code boolean} array, {@code null} if null array input
- * @throws NullPointerException if array content is {@code null}
- */
- public static boolean[] toPrimitive(final Boolean[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BOOLEAN_ARRAY;
- }
- final boolean[] result = new boolean[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = array[i].booleanValue();
- }
- return result;
- }
-
- /**
- *
Converts an array of object Booleans to primitives handling {@code null}.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code Boolean} array, may be {@code null}
- * @param valueForNull the value to insert if {@code null} found
- * @return a {@code boolean} array, {@code null} if null array input
- */
- public static boolean[] toPrimitive(final Boolean[] array, final boolean valueForNull) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BOOLEAN_ARRAY;
- }
- final boolean[] result = new boolean[array.length];
- for (int i = 0; i < array.length; i++) {
- final Boolean b = array[i];
- result[i] = (b == null ? valueForNull : b.booleanValue());
- }
- return result;
- }
-
- /**
- *
Converts an array of primitive booleans to objects.
- *
- *
This method returns {@code null} for a {@code null} input array.
- *
- * @param array a {@code boolean} array
- * @return a {@code Boolean} array, {@code null} if null array input
- */
- public static Boolean[] toObject(final boolean[] array) {
- if (array == null) {
- return null;
- } else if (array.length == 0) {
- return EMPTY_BOOLEAN_OBJECT_ARRAY;
- }
- final Boolean[] result = new Boolean[array.length];
- for (int i = 0; i < array.length; i++) {
- result[i] = (array[i] ? Boolean.TRUE : Boolean.FALSE);
- }
- return result;
- }
-
- // ----------------------------------------------------------------------
- /**
- *
Checks if an array of Objects is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final Object[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive longs is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final long[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive ints is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final int[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive shorts is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final short[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive chars is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final char[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive bytes is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final byte[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive doubles is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final double[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive floats is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final float[] array) {
- return getLength(array) == 0;
- }
-
- /**
- *
Checks if an array of primitive booleans is empty or {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is empty or {@code null}
- * @since 2.1
- */
- public static boolean isEmpty(final boolean[] array) {
- return getLength(array) == 0;
- }
-
- // ----------------------------------------------------------------------
- /**
- *
Checks if an array of Objects is not empty or not {@code null}.
- *
- * @param the component type of the array
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final T[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive longs is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final long[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive ints is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final int[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive shorts is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final short[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive chars is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final char[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive bytes is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final byte[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive doubles is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final double[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive floats is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final float[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Checks if an array of primitive booleans is not empty or not {@code null}.
- *
- * @param array the array to test
- * @return {@code true} if the array is not empty or not {@code null}
- * @since 2.5
- */
- public static boolean isNotEmpty(final boolean[] array) {
- return !isEmpty(array);
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param the component type of the array
- * @param array1 the first array whose elements are added to the new array, may be {@code null}
- * @param array2 the second array whose elements are added to the new array, may be {@code null}
- * @return The new array, {@code null} if both arrays are {@code null}.
- * The type of the new array is the type of the first array,
- * unless the first array is null, in which case the type is the same as the second array.
- * @since 2.1
- * @throws IllegalArgumentException if the array types are incompatible
- */
- public static T[] addAll(final T[] array1, final T... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final Class> type1 = array1.getClass().getComponentType();
- @SuppressWarnings("unchecked") // OK, because array is of type T
- final
- T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length);
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- try {
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- } catch (final ArrayStoreException ase) {
- // Check if problem was due to incompatible types
- /*
- * We do this here, rather than before the copy because:
- * - it would be a wasted check most of the time
- * - safer, in case check turns out to be too strict
- */
- final Class> type2 = array2.getClass().getComponentType();
- if (!type1.isAssignableFrom(type2)){
- throw new IllegalArgumentException("Cannot store "+type2.getName()+" in an array of "
- +type1.getName(), ase);
- }
- throw ase; // No, so rethrow original
- }
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new boolean[] array.
- * @since 2.1
- */
- public static boolean[] addAll(final boolean[] array1, final boolean... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final boolean[] joinedArray = new boolean[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new char[] array.
- * @since 2.1
- */
- public static char[] addAll(final char[] array1, final char... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final char[] joinedArray = new char[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new byte[] array.
- * @since 2.1
- */
- public static byte[] addAll(final byte[] array1, final byte... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final byte[] joinedArray = new byte[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new short[] array.
- * @since 2.1
- */
- public static short[] addAll(final short[] array1, final short... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final short[] joinedArray = new short[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new int[] array.
- * @since 2.1
- */
- public static int[] addAll(final int[] array1, final int... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final int[] joinedArray = new int[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new long[] array.
- * @since 2.1
- */
- public static long[] addAll(final long[] array1, final long... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final long[] joinedArray = new long[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new float[] array.
- * @since 2.1
- */
- public static float[] addAll(final float[] array1, final float... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final float[] joinedArray = new float[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Adds all the elements of the given arrays into a new array.
- *
The new array contains all of the element of {@code array1} followed
- * by all of the elements {@code array2}. When an array is returned, it is always
- * a new array.
- *
- * @param array1 the first array whose elements are added to the new array.
- * @param array2 the second array whose elements are added to the new array.
- * @return The new double[] array.
- * @since 2.1
- */
- public static double[] addAll(final double[] array1, final double... array2) {
- if (array1 == null) {
- return clone(array2);
- } else if (array2 == null) {
- return clone(array1);
- }
- final double[] joinedArray = new double[array1.length + array2.length];
- System.arraycopy(array1, 0, joinedArray, 0, array1.length);
- System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
- return joinedArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element, unless the element itself is null,
- * in which case the return type is Object[]
- *
- * @param the component type of the array
- * @param array the array to "add" the element to, may be {@code null}
- * @param element the object to add, may be {@code null}
- * @return A new array containing the existing elements plus the new element
- * The returned array type will be that of the input array (unless null),
- * in which case it will have the same type as the element.
- * If both are null, an IllegalArgumentException is thrown
- * @since 2.1
- * @throws IllegalArgumentException if both arguments are null
- */
- public static T[] add(final T[] array, final T element) {
- Class> type;
- if (array != null){
- type = array.getClass().getComponentType();
- } else if (element != null) {
- type = element.getClass();
- } else {
- throw new IllegalArgumentException("Arguments cannot both be null");
- }
- @SuppressWarnings("unchecked") // type must be T
- final
- T[] newArray = (T[]) copyArrayGrow1(array, type);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static boolean[] add(final boolean[] array, final boolean element) {
- final boolean[] newArray = (boolean[])copyArrayGrow1(array, Boolean.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static byte[] add(final byte[] array, final byte element) {
- final byte[] newArray = (byte[])copyArrayGrow1(array, Byte.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static char[] add(final char[] array, final char element) {
- final char[] newArray = (char[])copyArrayGrow1(array, Character.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static double[] add(final double[] array, final double element) {
- final double[] newArray = (double[])copyArrayGrow1(array, Double.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static float[] add(final float[] array, final float element) {
- final float[] newArray = (float[])copyArrayGrow1(array, Float.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static int[] add(final int[] array, final int element) {
- final int[] newArray = (int[])copyArrayGrow1(array, Integer.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static long[] add(final long[] array, final long element) {
- final long[] newArray = (long[])copyArrayGrow1(array, Long.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- *
Copies the given array and adds the given element at the end of the new array.
- *
- *
The new array contains the same elements of the input
- * array plus the given element in the last position. The component type of
- * the new array is the same as that of the input array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to copy and add the element to, may be {@code null}
- * @param element the object to add at the last index of the new array
- * @return A new array containing the existing elements plus the new element
- * @since 2.1
- */
- public static short[] add(final short[] array, final short element) {
- final short[] newArray = (short[])copyArrayGrow1(array, Short.TYPE);
- newArray[newArray.length - 1] = element;
- return newArray;
- }
-
- /**
- * Returns a copy of the given array of size 1 greater than the argument.
- * The last value of the array is left to the default value.
- *
- * @param array The array to copy, must not be {@code null}.
- * @param newArrayComponentType If {@code array} is {@code null}, create a
- * size 1 array of this type.
- * @return A new copy of the array of size 1 greater than the input.
- */
- private static Object copyArrayGrow1(final Object array, final Class> newArrayComponentType) {
- if (array != null) {
- final int arrayLength = Array.getLength(array);
- final Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
- System.arraycopy(array, 0, newArray, 0, arrayLength);
- return newArray;
- }
- return Array.newInstance(newArrayComponentType, 1);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param the component type of the array
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length).
- * @throws IllegalArgumentException if both array and element are null
- */
- public static T[] add(final T[] array, final int index, final T element) {
- Class> clss = null;
- if (array != null) {
- clss = array.getClass().getComponentType();
- } else if (element != null) {
- clss = element.getClass();
- } else {
- throw new IllegalArgumentException("Array and element cannot both be null");
- }
- @SuppressWarnings("unchecked") // the add method creates an array of type clss, which is type T
- final T[] newArray = (T[]) add(array, index, element, clss);
- return newArray;
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length).
- */
- public static boolean[] add(final boolean[] array, final int index, final boolean element) {
- return (boolean[]) add(array, index, Boolean.valueOf(element), Boolean.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static char[] add(final char[] array, final int index, final char element) {
- return (char[]) add(array, index, Character.valueOf(element), Character.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static byte[] add(final byte[] array, final int index, final byte element) {
- return (byte[]) add(array, index, Byte.valueOf(element), Byte.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static short[] add(final short[] array, final int index, final short element) {
- return (short[]) add(array, index, Short.valueOf(element), Short.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static int[] add(final int[] array, final int index, final int element) {
- return (int[]) add(array, index, Integer.valueOf(element), Integer.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static long[] add(final long[] array, final int index, final long element) {
- return (long[]) add(array, index, Long.valueOf(element), Long.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static float[] add(final float[] array, final int index, final float element) {
- return (float[]) add(array, index, Float.valueOf(element), Float.TYPE);
- }
-
- /**
- *
Inserts the specified element at the specified position in the array.
- * Shifts the element currently at that position (if any) and any subsequent
- * elements to the right (adds one to their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array plus the given element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, a new one element array is returned
- * whose component type is the same as the element.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @return A new array containing the existing elements and the new element
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index > array.length).
- */
- public static double[] add(final double[] array, final int index, final double element) {
- return (double[]) add(array, index, Double.valueOf(element), Double.TYPE);
- }
-
- /**
- * Underlying implementation of add(array, index, element) methods.
- * The last parameter is the class, which may not equal element.getClass
- * for primitives.
- *
- * @param array the array to add the element to, may be {@code null}
- * @param index the position of the new object
- * @param element the object to add
- * @param clss the type of the element being added
- * @return A new array containing the existing elements and the new element
- */
- private static Object add(final Object array, final int index, final Object element, final Class> clss) {
- if (array == null) {
- if (index != 0) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0");
- }
- final Object joinedArray = Array.newInstance(clss, 1);
- Array.set(joinedArray, 0, element);
- return joinedArray;
- }
- final int length = Array.getLength(array);
- if (index > length || index < 0) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
- }
- final Object result = Array.newInstance(clss, length + 1);
- System.arraycopy(array, 0, result, 0, index);
- Array.set(result, index, element);
- if (index < length) {
- System.arraycopy(array, index, result, index + 1, length - index);
- }
- return result;
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param the component type of the array
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input
- public static T[] remove(final T[] array, final int index) {
- return (T[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param the component type of the array
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static T[] removeElement(final T[] array, final Object element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static boolean[] remove(final boolean[] array, final int index) {
- return (boolean[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static boolean[] removeElement(final boolean[] array, final boolean element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static byte[] remove(final byte[] array, final int index) {
- return (byte[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static byte[] removeElement(final byte[] array, final byte element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static char[] remove(final char[] array, final int index) {
- return (char[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static char[] removeElement(final char[] array, final char element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static double[] remove(final double[] array, final int index) {
- return (double[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static double[] removeElement(final double[] array, final double element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static float[] remove(final float[] array, final int index) {
- return (float[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static float[] removeElement(final float[] array, final float element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static int[] remove(final int[] array, final int index) {
- return (int[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static int[] removeElement(final int[] array, final int element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static long[] remove(final long[] array, final int index) {
- return (long[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static long[] removeElement(final long[] array, final long element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- public static short[] remove(final short[] array, final int index) {
- return (short[]) remove((Object) array, index);
- }
-
- /**
- *
Removes the first occurrence of the specified element from the
- * specified array. All subsequent elements are shifted to the left
- * (subtracts one from their indices). If the array doesn't contains
- * such an element, no elements are removed from the array.
- *
- *
This method returns a new array with the same elements of the input
- * array except the first occurrence of the specified element. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param element the element to be removed
- * @return A new array containing the existing elements except the first
- * occurrence of the specified element.
- * @since 2.1
- */
- public static short[] removeElement(final short[] array, final short element) {
- final int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
- return remove(array, index);
- }
-
- /**
- *
Removes the element at the specified position from the specified array.
- * All subsequent elements are shifted to the left (subtracts one from
- * their indices).
- *
- *
This method returns a new array with the same elements of the input
- * array except the element on the specified position. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param index the position of the element to be removed
- * @return A new array containing the existing elements except the element
- * at the specified position.
- * @throws IndexOutOfBoundsException if the index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 2.1
- */
- private static Object remove(final Object array, final int index) {
- final int length = getLength(array);
- if (index < 0 || index >= length) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
- }
-
- final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
- System.arraycopy(array, 0, result, 0, index);
- if (index < length - 1) {
- System.arraycopy(array, index + 1, result, index, length - index - 1);
- }
-
- return result;
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param the component type of the array
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input
- public static T[] removeAll(final T[] array, final int... indices) {
- return (T[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param the component type of the array
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static T[] removeElements(final T[] array, final T... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final T v : values) {
- final MutableInt count = occurrences.get(v);
- if (count == null) {
- occurrences.put(v, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final T v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v, found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input
- final
- T[] result = (T[]) removeAll(array, toRemove);
- return result;
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static byte[] removeAll(final byte[] array, final int... indices) {
- return (byte[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static byte[] removeElements(final byte[] array, final byte... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final Map occurrences = new HashMap(values.length);
- for (final byte v : values) {
- final Byte boxed = Byte.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Byte v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.byteValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (byte[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static short[] removeAll(final short[] array, final int... indices) {
- return (short[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static short[] removeElements(final short[] array, final short... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final short v : values) {
- final Short boxed = Short.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Short v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.shortValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (short[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static int[] removeAll(final int[] array, final int... indices) {
- return (int[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static int[] removeElements(final int[] array, final int... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final int v : values) {
- final Integer boxed = Integer.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Integer v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.intValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (int[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static char[] removeAll(final char[] array, final int... indices) {
- return (char[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static char[] removeElements(final char[] array, final char... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final char v : values) {
- final Character boxed = Character.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Character v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.charValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (char[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static long[] removeAll(final long[] array, final int... indices) {
- return (long[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static long[] removeElements(final long[] array, final long... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final long v : values) {
- final Long boxed = Long.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Long v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.longValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (long[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static float[] removeAll(final float[] array, final int... indices) {
- return (float[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static float[] removeElements(final float[] array, final float... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final float v : values) {
- final Float boxed = Float.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Float v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.floatValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (float[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static double[] removeAll(final double[] array, final int... indices) {
- return (double[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static double[] removeElements(final double[] array, final double... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(values.length);
- for (final double v : values) {
- final Double boxed = Double.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Double v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.doubleValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (double[]) removeAll(array, toRemove);
- }
-
- /**
- *
Removes the elements at the specified positions from the specified array.
- * All remaining elements are shifted to the left.
- *
- *
This method returns a new array with the same elements of the input
- * array except those at the specified positions. The component
- * type of the returned array is always the same as that of the input
- * array.
- *
- *
If the input array is {@code null}, an IndexOutOfBoundsException
- * will be thrown, because in that case no valid index can be specified.
- *
- * @param array the array to remove the element from, may not be {@code null}
- * @param indices the positions of the elements to be removed
- * @return A new array containing the existing elements except those
- * at the specified positions.
- * @throws IndexOutOfBoundsException if any index is out of range
- * (index < 0 || index >= array.length), or if the array is {@code null}.
- * @since 3.0.1
- */
- public static boolean[] removeAll(final boolean[] array, final int... indices) {
- return (boolean[]) removeAll((Object) array, clone(indices));
- }
-
- /**
- *
Removes occurrences of specified elements, in specified quantities,
- * from the specified array. All subsequent elements are shifted left.
- * For any element-to-be-removed specified in greater quantities than
- * contained in the original array, no change occurs beyond the
- * removal of the existing matching items.
- *
- *
This method returns a new array with the same elements of the input
- * array except for the earliest-encountered occurrences of the specified
- * elements. The component type of the returned array is always the same
- * as that of the input array.
- *
- * @param array the array to remove the element from, may be {@code null}
- * @param values the elements to be removed
- * @return A new array containing the existing elements except the
- * earliest-encountered occurrences of the specified elements.
- * @since 3.0.1
- */
- public static boolean[] removeElements(final boolean[] array, final boolean... values) {
- if (isEmpty(array) || isEmpty(values)) {
- return clone(array);
- }
- final HashMap occurrences = new HashMap(2); // only two possible values here
- for (final boolean v : values) {
- final Boolean boxed = Boolean.valueOf(v);
- final MutableInt count = occurrences.get(boxed);
- if (count == null) {
- occurrences.put(boxed, new MutableInt(1));
- } else {
- count.increment();
- }
- }
- final BitSet toRemove = new BitSet();
- for (final Map.Entry e : occurrences.entrySet()) {
- final Boolean v = e.getKey();
- int found = 0;
- for (int i = 0, ct = e.getValue().intValue(); i < ct; i++) {
- found = indexOf(array, v.booleanValue(), found);
- if (found < 0) {
- break;
- }
- toRemove.set(found++);
- }
- }
- return (boolean[]) removeAll(array, toRemove);
- }
-
- /**
- * Removes multiple array elements specified by index.
- * @param array source
- * @param indices to remove, WILL BE SORTED--so only clones of user-owned arrays!
- * @return new array of same type minus elements specified by unique values of {@code indices}
- * @since 3.0.1
- */
- // package protected for access by unit tests
- static Object removeAll(final Object array, final int... indices) {
- final int length = getLength(array);
- int diff = 0; // number of distinct indexes, i.e. number of entries that will be removed
-
- if (isNotEmpty(indices)) {
- Arrays.sort(indices);
-
- int i = indices.length;
- int prevIndex = length;
- while (--i >= 0) {
- final int index = indices[i];
- if (index < 0 || index >= length) {
- throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
- }
- if (index >= prevIndex) {
- continue;
- }
- diff++;
- prevIndex = index;
- }
- }
- final Object result = Array.newInstance(array.getClass().getComponentType(), length - diff);
- if (diff < length) {
- int end = length; // index just after last copy
- int dest = length - diff; // number of entries so far not copied
- for (int i = indices.length - 1; i >= 0; i--) {
- final int index = indices[i];
- if (end - index > 1) { // same as (cp > 0)
- final int cp = end - index - 1;
- dest -= cp;
- System.arraycopy(array, index + 1, result, dest, cp);
- // Afer this copy, we still have room for dest items.
- }
- end = index;
- }
- if (end > 0) {
- System.arraycopy(array, 0, result, 0, end);
- }
- }
- return result;
- }
-
- /**
- * Removes multiple array elements specified by indices.
- *
- * @param array source
- * @param indices to remove
- * @return new array of same type minus elements specified by the set bits in {@code indices}
- * @since 3.2
- */
- // package protected for access by unit tests
- static Object removeAll(final Object array, final BitSet indices) {
- final int srcLength = ArrayUtils.getLength(array);
- // No need to check maxIndex here, because method only currently called from removeElements()
- // which guarantee to generate on;y valid bit entries.
-// final int maxIndex = indices.length();
-// if (maxIndex > srcLength) {
-// throw new IndexOutOfBoundsException("Index: " + (maxIndex-1) + ", Length: " + srcLength);
-// }
- final int removals = indices.cardinality(); // true bits are items to remove
- final Object result = Array.newInstance(array.getClass().getComponentType(), srcLength - removals);
- int srcIndex=0;
- int destIndex=0;
- int count;
- int set;
- while((set = indices.nextSetBit(srcIndex)) != -1){
- count = set - srcIndex;
- if (count > 0) {
- System.arraycopy(array, srcIndex, result, destIndex, count);
- destIndex += count;
- }
- srcIndex = indices.nextClearBit(set);
- }
- count = srcLength - srcIndex;
- if (count > 0) {
- System.arraycopy(array, srcIndex, result, destIndex, count);
- }
- return result;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to the class's
- * {@code compareTo} method.
- *
- * @param array the array to check
- * @param the datatype of the array to check, it must implement {@code Comparable}
- * @return whether the array is sorted
- * @since 3.4
- */
- public static > boolean isSorted(final T[] array) {
- return isSorted(array, new Comparator() {
- @Override
- public int compare(T o1, T o2) {
- return o1.compareTo(o2);
- }
- });
- }
-
-
- /**
- *
This method checks whether the provided array is sorted according to the provided {@code Comparator}.
- *
- * @param array the array to check
- * @param comparator the {@code Comparator} to compare over
- * @param the datatype of the array
- * @return whether the array is sorted
- * @since 3.4
- */
- public static boolean isSorted(final T[] array, final Comparator comparator) {
- if (comparator == null) {
- throw new IllegalArgumentException("Comparator should not be null.");
- }
-
- if(array == null || array.length < 2) {
- return true;
- }
-
- T previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final T current = array[i];
- if (comparator.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(int[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- int previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final int current = array[i];
- if(NumberUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(long[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- long previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final long current = array[i];
- if(NumberUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(short[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- short previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final short current = array[i];
- if(NumberUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(final double[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- double previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final double current = array[i];
- if(Double.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(final float[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- float previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final float current = array[i];
- if(Float.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(byte[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- byte previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final byte current = array[i];
- if(NumberUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering.
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(char[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- char previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final char current = array[i];
- if(CharUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
This method checks whether the provided array is sorted according to natural ordering
- * ({@code false} before {@code true}).
- *
- * @param array the array to check
- * @return whether the array is sorted according to natural ordering
- * @since 3.4
- */
- public static boolean isSorted(boolean[] array) {
- if(array == null || array.length < 2) {
- return true;
- }
-
- boolean previous = array[0];
- final int n = array.length;
- for(int i = 1; i < n; i++) {
- final boolean current = array[i];
- if(BooleanUtils.compare(previous, current) > 0) {
- return false;
- }
-
- previous = current;
- }
- return true;
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static boolean[] removeAllOccurences(final boolean[] array, final boolean element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static char[] removeAllOccurences(final char[] array, final char element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static byte[] removeAllOccurences(final byte[] array, final byte element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static short[] removeAllOccurences(final short[] array, final short element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static int[] removeAllOccurences(final int[] array, final int element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static long[] removeAllOccurences(final long[] array, final long element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static float[] removeAllOccurences(final float[] array, final float element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static double[] removeAllOccurences(final double[] array, final double element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-
- /**
- *
- * Removes the occurrences of the specified element from the specified array. All subsequent elements are shifted to
- * the left (subtracts one from their indices). If the array doesn't contains such an element, no elements are
- * removed from the array. null will be returned if the input array is null
- *
- *
- * @param the type of object in the array
- * @param element the element to remove
- * @param array the input array
- *
- * @return A new array containing the existing elements except the occurrences of the specified element.
- * @since 3.5
- */
- public static T[] removeAllOccurences(final T[] array, final T element) {
- int index = indexOf(array, element);
- if (index == INDEX_NOT_FOUND) {
- return clone(array);
- }
-
- int[] indices = new int[array.length - index];
- indices[0] = index;
- int count = 1;
-
- while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) {
- indices[count++] = index;
- }
-
- return removeAll(array, Arrays.copyOf(indices, count));
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.commons.lang3.function.FailableFunction;
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.apache.commons.lang3.stream.IntStreams;
+import org.apache.commons.lang3.stream.Streams;
+
+/**
+ * Operations on arrays, primitive arrays (like {@code int[]}) and
+ * primitive wrapper arrays (like {@code Integer[]}).
+ *
+ * This class tries to handle {@code null} input gracefully.
+ * An exception will not be thrown for a {@code null}
+ * array input. However, an Object array that contains a {@code null}
+ * element may throw an exception. Each method documents its behavior.
+ *
+ *
+ * #ThreadSafe#
+ *
+ *
+ * @since 2.0
+ */
+public class ArrayUtils {
+
+ /**
+ * Bridge class to {@link Math} methods for testing purposes.
+ */
+ static class MathBridge {
+ static int addExact(final int a, final int b) {
+ return Math.addExact(a, b);
+ }
+ }
+
+ /**
+ * An empty immutable {@code boolean} array.
+ */
+ public static final boolean[] EMPTY_BOOLEAN_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Boolean} array.
+ */
+ public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code byte} array.
+ */
+ public static final byte[] EMPTY_BYTE_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Byte} array.
+ */
+ public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code char} array.
+ */
+ public static final char[] EMPTY_CHAR_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Character} array.
+ */
+ public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Class} array.
+ */
+ public static final Class>[] EMPTY_CLASS_ARRAY = {};
+
+ /**
+ * An empty immutable {@code double} array.
+ */
+ public static final double[] EMPTY_DOUBLE_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Double} array.
+ */
+ public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Field} array.
+ *
+ * @since 3.10
+ */
+ public static final Field[] EMPTY_FIELD_ARRAY = {};
+
+ /**
+ * An empty immutable {@code float} array.
+ */
+ public static final float[] EMPTY_FLOAT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Float} array.
+ */
+ public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code int} array.
+ */
+ public static final int[] EMPTY_INT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Integer} array.
+ */
+ public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code long} array.
+ */
+ public static final long[] EMPTY_LONG_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Long} array.
+ */
+ public static final Long[] EMPTY_LONG_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Method} array.
+ *
+ * @since 3.10
+ */
+ public static final Method[] EMPTY_METHOD_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Object} array.
+ */
+ public static final Object[] EMPTY_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code short} array.
+ */
+ public static final short[] EMPTY_SHORT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Short} array.
+ */
+ public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link String} array.
+ */
+ public static final String[] EMPTY_STRING_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Throwable} array.
+ *
+ * @since 3.10
+ */
+ public static final Throwable[] EMPTY_THROWABLE_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Type} array.
+ *
+ * @since 3.10
+ */
+ public static final Type[] EMPTY_TYPE_ARRAY = {};
+
+ /**
+ * The index value when an element is not found in a list or array: {@code -1}.
+ * This value is returned by methods in this class and can also be used in comparisons with values returned by
+ * various method from {@link java.util.List}.
+ */
+ public static final int INDEX_NOT_FOUND = -1;
+
+ /**
+ * The {@code SOFT_MAX_ARRAY_LENGTH} constant from Java's internal ArraySupport class.
+ *
+ * @since 3.19.0
+ * @deprecated This variable will be final in 4.0; to guarantee immutability now, use {@link #SAFE_MAX_ARRAY_LENGTH}.
+ */
+ @Deprecated
+ public static int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
+
+ /**
+ * The {@code MAX_ARRAY_LENGTH} constant from Java's internal ArraySupport class.
+ *
+ * @since 3.21.0
+ */
+ public static final int SAFE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static boolean[] add(final boolean[] array, final boolean element) {
+ final boolean[] newArray = (boolean[]) copyArrayGrow1(array, Boolean.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, boolean[], boolean...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static boolean[] add(final boolean[] array, final int index, final boolean element) {
+ return (boolean[]) add(array, index, Boolean.valueOf(element), Boolean.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static byte[] add(final byte[] array, final byte element) {
+ final byte[] newArray = (byte[]) copyArrayGrow1(array, Byte.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range.
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, byte[], byte...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static byte[] add(final byte[] array, final int index, final byte element) {
+ return (byte[]) add(array, index, Byte.valueOf(element), Byte.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static char[] add(final char[] array, final char element) {
+ final char[] newArray = (char[]) copyArrayGrow1(array, Character.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range.
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, char[], char...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static char[] add(final char[] array, final int index, final char element) {
+ return (char[]) add(array, index, Character.valueOf(element), Character.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static double[] add(final double[] array, final double element) {
+ final double[] newArray = (double[]) copyArrayGrow1(array, Double.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, double[], double...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static double[] add(final double[] array, final int index, final double element) {
+ return (double[]) add(array, index, Double.valueOf(element), Double.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static float[] add(final float[] array, final float element) {
+ final float[] newArray = (float[]) copyArrayGrow1(array, Float.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, float[], float...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static float[] add(final float[] array, final int index, final float element) {
+ return (float[]) add(array, index, Float.valueOf(element), Float.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static int[] add(final int[] array, final int element) {
+ final int[] newArray = (int[]) copyArrayGrow1(array, Integer.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, int[], int...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static int[] add(final int[] array, final int index, final int element) {
+ return (int[]) add(array, index, Integer.valueOf(element), Integer.TYPE);
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, long[], long...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static long[] add(final long[] array, final int index, final long element) {
+ return (long[]) add(array, index, Long.valueOf(element), Long.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static long[] add(final long[] array, final long element) {
+ final long[] newArray = (long[]) copyArrayGrow1(array, Long.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Underlying implementation of add(array, index, element) methods.
+ * The last parameter is the class, which may not equal element.getClass
+ * for primitives.
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @param clazz the type of the element being added.
+ * @return A new array containing the existing elements and the new element.
+ */
+ private static Object add(final Object array, final int index, final Object element, final Class> clazz) {
+ if (array == null) {
+ if (index != 0) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0");
+ }
+ final Object joinedArray = Array.newInstance(clazz, 1);
+ Array.set(joinedArray, 0, element);
+ return joinedArray;
+ }
+ final int length = Array.getLength(array);
+ if (index > length || index < 0) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+ }
+ final Object result = arraycopy(array, 0, 0, index, () -> Array.newInstance(clazz, length + 1));
+ Array.set(result, index, element);
+ if (index < length) {
+ System.arraycopy(array, index, result, index + 1, length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index > array.length).
+ * @deprecated this method has been superseded by {@link #insert(int, short[], short...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static short[] add(final short[] array, final int index, final short element) {
+ return (short[]) add(array, index, Short.valueOf(element), Short.TYPE);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}.
+ * @param element the object to add at the last index of the new array.
+ * @return A new array containing the existing elements plus the new element.
+ * @since 2.1
+ */
+ public static short[] add(final short[] array, final short element) {
+ final short[] newArray = (short[]) copyArrayGrow1(array, Short.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in the array.
+ * Shifts the element currently at that position (if any) and any subsequent
+ * elements to the right (adds one to their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array plus the given element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to add the element to, may be {@code null}.
+ * @param index the position of the new object.
+ * @param element the object to add.
+ * @return A new array containing the existing elements and the new element.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length).
+ * @throws IllegalArgumentException if both array and element are null.
+ * @deprecated this method has been superseded by {@link #insert(int, Object[], Object...) insert(int, T[], T...)} and
+ * may be removed in a future release. Please note the handling of {@code null} input arrays differs
+ * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}.
+ */
+ @Deprecated
+ public static T[] add(final T[] array, final int index, final T element) {
+ final Class clazz;
+ if (array != null) {
+ clazz = getComponentType(array);
+ } else if (element != null) {
+ clazz = ObjectUtils.getClass(element);
+ } else {
+ throw new IllegalArgumentException("Array and element cannot both be null");
+ }
+ return (T[]) add(array, index, element, clazz);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element, unless the element itself is null,
+ * in which case the return type is Object[]
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add, may be {@code null}.
+ * @return A new array containing the existing elements plus the new element
+ * The returned array type will be that of the input array (unless null),
+ * in which case it will have the same type as the element.
+ * If both are null, an IllegalArgumentException is thrown.
+ * @throws IllegalArgumentException if both arguments are null.
+ * @since 2.1
+ */
+ public static T[] add(final T[] array, final T element) {
+ final Class> type;
+ if (array != null) {
+ type = array.getClass().getComponentType();
+ } else if (element != null) {
+ type = element.getClass();
+ } else {
+ throw new IllegalArgumentException("Arguments cannot both be null");
+ }
+ @SuppressWarnings("unchecked") // type must be T
+ final
+ T[] newArray = (T[]) copyArrayGrow1(array, type);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new boolean[] array or {@code null}.
+ * @since 2.1
+ */
+ public static boolean[] addAll(final boolean[] array1, final boolean... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final boolean[] joinedArray = new boolean[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new byte[] array or {@code null}.
+ * @since 2.1
+ */
+ public static byte[] addAll(final byte[] array1, final byte... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final byte[] joinedArray = new byte[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new char[] array or {@code null}.
+ * @since 2.1
+ */
+ public static char[] addAll(final char[] array1, final char... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final char[] joinedArray = new char[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new double[] array or {@code null}.
+ * @since 2.1
+ */
+ public static double[] addAll(final double[] array1, final double... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final double[] joinedArray = new double[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new float[] array or {@code null}.
+ * @since 2.1
+ */
+ public static float[] addAll(final float[] array1, final float... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final float[] joinedArray = new float[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new int[] array or {@code null}.
+ * @since 2.1
+ */
+ public static int[] addAll(final int[] array1, final int... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final int[] joinedArray = new int[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new long[] array or {@code null}.
+ * @since 2.1
+ */
+ public static long[] addAll(final long[] array1, final long... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final long[] joinedArray = new long[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new short[] array or {@code null}.
+ * @since 2.1
+ */
+ public static short[] addAll(final short[] array1, final short... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final short[] joinedArray = new short[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param the component type of the array.
+ * @param array1 the first array whose elements are added to the new array, may be {@code null}.
+ * @param array2 the second array whose elements are added to the new array, may be {@code null}.
+ * @return The new array, {@code null} if both arrays are {@code null}.
+ * The type of the new array is the type of the first array,
+ * unless the first array is null, in which case the type is the same as the second array.
+ * @throws IllegalArgumentException if the array types are incompatible.
+ * @since 2.1
+ */
+ public static T[] addAll(final T[] array1, @SuppressWarnings("unchecked") final T... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final Class type1 = getComponentType(array1);
+ final T[] joinedArray = arraycopy(array1, 0, 0, array1.length, () -> newInstance(type1, array1.length + array2.length));
+ try {
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ } catch (final ArrayStoreException ase) {
+ // Check if problem was due to incompatible types
+ /*
+ * We do this here, rather than before the copy because: - it would be a wasted check most of the time - safer, in case check turns out to be too
+ * strict
+ */
+ final Class> type2 = array2.getClass().getComponentType();
+ if (!type1.isAssignableFrom(type2)) {
+ throw new IllegalArgumentException("Cannot store " + type2.getName() + " in an array of " + type1.getName(), ase);
+ }
+ throw ase; // No, so rethrow original
+ }
+ return joinedArray;
+ }
+
+ /**
+ * Safely adds the length of an array to a running total, checking for overflow.
+ *
+ * @param totalLength the current accumulated length
+ * @param array the array whose length should be added (can be {@code null},
+ * in which case its length is considered 0)
+ * @return the new total length after adding the array's length
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ */
+ private static int addExact(final int totalLength, final Object array) {
+ try {
+ final int length = MathBridge.addExact(totalLength, getLength(array));
+ if (length > SAFE_MAX_ARRAY_LENGTH) {
+ throw new IllegalArgumentException("Total arrays length exceed " + SAFE_MAX_ARRAY_LENGTH);
+ }
+ return length;
+ } catch (final ArithmeticException exception) {
+ throw new IllegalArgumentException("Total arrays length exceed " + SAFE_MAX_ARRAY_LENGTH);
+ }
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static boolean[] addFirst(final boolean[] array, final boolean element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static byte[] addFirst(final byte[] array, final byte element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static char[] addFirst(final char[] array, final char element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static double[] addFirst(final double[] array, final double element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static float[] addFirst(final float[] array, final float element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static int[] addFirst(final int[] array, final int element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static long[] addFirst(final long[] array, final long element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static short[] addFirst(final short[] array, final short element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element, unless the element itself is null, in which case the return type is Object[]
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add, may be {@code null}.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element. If both are null,
+ * an IllegalArgumentException is thrown.
+ * @throws IllegalArgumentException if both arguments are null.
+ * @since 3.10
+ */
+ public static T[] addFirst(final T[] array, final T element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type.
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @param allocator allocates the array to populate and return.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final int destPos, final int length, final Function allocator) {
+ return arraycopy(source, sourcePos, allocator.apply(length), destPos, length);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type.
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @param allocator allocates the array to populate and return.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final int destPos, final int length, final Supplier allocator) {
+ return arraycopy(source, sourcePos, allocator.get(), destPos, length);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type.
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param dest the destination array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final T dest, final int destPos, final int length) {
+ System.arraycopy(source, sourcePos, dest, destPos, length);
+ return dest;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static boolean[] clone(final boolean[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static byte[] clone(final byte[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static char[] clone(final char[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static double[] clone(final double[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static float[] clone(final float[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static int[] clone(final int[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static long[] clone(final long[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static short[] clone(final short[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Shallow clones an array or returns {@code null}.
+ *
+ * The objects in the array are not cloned, thus there is no special handling for multi-dimensional arrays.
+ *
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to shallow clone, may be {@code null}.
+ * @return the cloned array, {@code null} if {@code null} input.
+ */
+ public static T[] clone(final T[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Concatenates multiple boolean arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new boolean array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static boolean[] concat(boolean[]... arrays) {
+ int totalLength = 0;
+ for (boolean[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final boolean[] result = new boolean[totalLength];
+ int currentPos = 0;
+ for (boolean[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple byte arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new byte array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static byte[] concat(byte[]... arrays) {
+ int totalLength = 0;
+ for (byte[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final byte[] result = new byte[totalLength];
+ int currentPos = 0;
+ for (byte[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple char arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new char array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static char[] concat(char[]... arrays) {
+ int totalLength = 0;
+ for (char[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final char[] result = new char[totalLength];
+ int currentPos = 0;
+ for (char[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple double arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new double array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static double[] concat(double[]... arrays) {
+ int totalLength = 0;
+ for (double[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final double[] result = new double[totalLength];
+ int currentPos = 0;
+ for (double[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple float arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new float array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static float[] concat(float[]... arrays) {
+ int totalLength = 0;
+ for (float[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final float[] result = new float[totalLength];
+ int currentPos = 0;
+ for (float[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple int arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new int array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static int[] concat(int[]... arrays) {
+ int totalLength = 0;
+ for (int[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final int[] result = new int[totalLength];
+ int currentPos = 0;
+ for (int[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple long arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new long array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static long[] concat(long[]... arrays) {
+ int totalLength = 0;
+ for (long[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final long[] result = new long[totalLength];
+ int currentPos = 0;
+ for (long[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Concatenates multiple short arrays into a single array.
+ *
+ * This method combines all input arrays in the order they are provided,
+ * creating a new array that contains all elements from the input arrays.
+ * The resulting array length is the sum of lengths of all non-null input arrays.
+ *
+ *
+ * @param arrays the arrays to concatenate. Can be empty, contain nulls,
+ * or be null itself (treated as empty varargs).
+ * @return a new short array containing all elements from the input arrays
+ * in the order they appear, or an empty array if no elements are present.
+ * @throws NullPointerException if the input array of arrays is null.
+ * @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
+ * @since 3.21.0
+ */
+ public static short[] concat(short[]... arrays) {
+ int totalLength = 0;
+ for (short[] array : arrays) {
+ totalLength = addExact(totalLength, array);
+ }
+ final short[] result = new short[totalLength];
+ int currentPos = 0;
+ for (short[] array : arrays) {
+ if (array != null && array.length > 0) {
+ System.arraycopy(array, 0, result, currentPos, array.length);
+ currentPos += array.length;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final boolean[] array, final boolean valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(byte[])} and {@link Arrays#binarySearch(byte[], byte)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final byte[] array, final byte valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(char[])} and {@link Arrays#binarySearch(char[], char)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ * @since 2.1
+ */
+ public static boolean contains(final char[] array, final char valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final double[] array, final double valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if a value falling within the given tolerance is in the
+ * given array. If the array contains a value within the inclusive range
+ * defined by (value - tolerance) to (value + tolerance).
+ *
+ * The method returns {@code false} if a {@code null} array
+ * is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @param tolerance the array contains the tolerance of the search.
+ * @return true if value falling within tolerance is in array.
+ */
+ public static boolean contains(final double[] array, final double valueToFind, final double tolerance) {
+ return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(float[])} and {@link Arrays#binarySearch(float[], float)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final float[] array, final float valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(int[])} and {@link Arrays#binarySearch(int[], int)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final int[] array, final int valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(long[])} and {@link Arrays#binarySearch(long[], long)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final long[] array, final long valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the object is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(Object[], Comparator)} and {@link Arrays#binarySearch(Object[], Object)}.
+ *
+ *
+ * @param array the array to search, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final Object[] array, final Object objectToFind) {
+ return indexOf(array, objectToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(short[])} and {@link Arrays#binarySearch(short[], short)}.
+ *
+ *
+ * @param array the array to search.
+ * @param valueToFind the value to find.
+ * @return {@code true} if the array contains the object.
+ */
+ public static boolean contains(final short[] array, final short valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if any of the ints are in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(int[])} and {@link Arrays#binarySearch(int[], int)}.
+ *
+ *
+ * @param array the array to search.
+ * @param objectsToFind any of the ints to find.
+ * @return {@code true} if the array contains any of the ints.
+ * @since 3.18.0
+ */
+ public static boolean containsAny(final int[] array, final int... objectsToFind) {
+ return IntStreams.of(objectsToFind).anyMatch(e -> contains(array, e));
+ }
+
+ /**
+ * Checks if any of the objects are in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(Object[], Comparator)} and {@link Arrays#binarySearch(Object[], Object)}.
+ *
+ *
+ * @param array the array to search, may be {@code null}.
+ * @param objectsToFind any of the objects to find, may be {@code null}.
+ * @return {@code true} if the array contains any of the objects.
+ * @since 3.13.0
+ */
+ public static boolean containsAny(final Object[] array, final Object... objectsToFind) {
+ return Streams.of(objectsToFind).anyMatch(e -> contains(array, e));
+ }
+
+ /**
+ * Returns a copy of the given array of size 1 greater than the argument.
+ * The last value of the array is left to the default value.
+ *
+ * @param array The array to copy, must not be {@code null}.
+ * @param newArrayComponentType If {@code array} is {@code null}, create a
+ * size 1 array of this type.
+ * @return A new copy of the array of size 1 greater than the input.
+ */
+ private static Object copyArrayGrow1(final Object array, final Class> newArrayComponentType) {
+ if (array != null) {
+ final int arrayLength = Array.getLength(array);
+ final Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
+ System.arraycopy(array, 0, newArray, 0, arrayLength);
+ return newArray;
+ }
+ return Array.newInstance(newArrayComponentType, 1);
+ }
+
+ /**
+ * Gets the nTh element of an array or null if the index is out of bounds or the array is null.
+ *
+ * @param The type of array elements.
+ * @param array The array to index.
+ * @param index The index.
+ * @return the nTh element of an array or null if the index is out of bounds or the array is null.
+ * @since 3.11
+ */
+ public static T get(final T[] array, final int index) {
+ return get(array, index, null);
+ }
+
+ /**
+ * Gets the nTh element of an array or a default value if the index is out of bounds.
+ *
+ * @param The type of array elements.
+ * @param array The array to index.
+ * @param index The index.
+ * @param defaultValue The return value of the given index is out of bounds.
+ * @return the nTh element of an array or a default value if the index is out of bounds.
+ * @since 3.11
+ */
+ public static T get(final T[] array, final int index, final T defaultValue) {
+ return isArrayIndexValid(array, index) ? array[index] : defaultValue;
+ }
+
+ /**
+ * Gets an array's component type.
+ *
+ * @param The array type.
+ * @param array The array.
+ * @return The component type.
+ * @since 3.13.0
+ */
+ public static Class getComponentType(final T[] array) {
+ return ClassUtils.getComponentType(ObjectUtils.getClass(array));
+ }
+
+ /**
+ * Gets the number of dimensions of an array.
+ *
+ * The JVM specification limits the number of dimensions to 255.
+ *
+ *
+ * @param array the array, may be {@code null}.
+ * @return The number of dimensions, 0 if the input is null or not an array. The JVM specification limits the number of dimensions to 255.
+ * @since 3.21.0
+ * @see JVM specification Field Descriptors
+ */
+ public static int getDimensions(final Object array) {
+ int dimensions = 0;
+ if (array != null) {
+ Class> arrayClass = array.getClass();
+ while (arrayClass.isArray()) {
+ dimensions++;
+ arrayClass = arrayClass.getComponentType();
+ }
+ }
+ return dimensions;
+ }
+
+ /**
+ * Gets the length of the specified array.
+ * This method handles {@link Object} arrays and primitive arrays.
+ *
+ * If the input array is {@code null}, {@code 0} is returned.
+ *
+ *
+ * @param array the array to retrieve the length from, may be {@code null}.
+ * @return The length of the array, or {@code 0} if the array is {@code null}.
+ * @throws IllegalArgumentException if the object argument is not an array.
+ * @since 2.1
+ */
+ public static int getLength(final Object array) {
+ return array != null ? Array.getLength(array) : 0;
+ }
+
+ /**
+ * Gets a hash code for an array handling multidimensional arrays.
+ *
+ * Multi-dimensional primitive arrays are also handled by this method.
+ *
+ *
+ * @param array the array to get a hash code for, may be {@code null}.
+ * @return a hash code for the array.
+ * @see HashCodeBuilder
+ */
+ public static int hashCode(final Object array) {
+ return new HashCodeBuilder().append(array).toHashCode();
+ }
+
+ static void increment(final Map occurrences, final K boxed) {
+ occurrences.computeIfAbsent(boxed, k -> new MutableInt()).increment();
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ * This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final boolean[] array, final boolean valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ * This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return an empty BitSet ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array, an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final boolean[] array, final boolean valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
+ * This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array, an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final byte[] array, final byte valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final byte[] array, final byte valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final char[] array, final char valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final char[] array, final char valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value within a given tolerance in the array.
+ *
+ *
+ * This method will return all the indices of the value which fall between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance, each time between the nearest integers.
+ *
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param tolerance tolerance of the search.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, final double tolerance) {
+ return indexesOf(array, valueToFind, 0, tolerance);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
+ * This method will return the indices of the values which fall between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance, between the nearest integers.
+ *
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @param tolerance tolerance of the search.
+ * @return a BitSet of the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex, tolerance);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final float[] array, final float valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final float[] array, final float valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final int[] array, final int valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final int[] array, final int valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final long[] array, final long valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final long[] array, final long valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given object in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return a BitSet of all the indices of the object within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final Object[] array, final Object objectToFind) {
+ return indexesOf(array, objectToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given object in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the object within the array starting at the index,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final Object[] array, final Object objectToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, objectToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final short[] array, final short valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input.
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final short[] array, final short valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array != null) {
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final boolean[] array, final boolean valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final boolean[] array, final boolean valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final byte[] array, final byte valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final byte[] array, final byte valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ * @since 2.1
+ */
+ public static int indexOf(final char[] array, final char valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ * @since 2.1
+ */
+ public static int indexOf(final char[] array, final char valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final double[] array, final double valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value within a given tolerance in the array. This method will return the index of the first value which falls between the
+ * region defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param tolerance tolerance of the search.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final double tolerance) {
+ return indexOf(array, valueToFind, 0, tolerance);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final int startIndex) {
+ if (Double.isNaN(valueToFind)) {
+ return indexOfNaN(array, startIndex);
+ }
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index. This method will return the index of the first value which falls between the
+ * region defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @param tolerance tolerance of the search.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final int startIndex, final double tolerance) {
+ if (Double.isNaN(valueToFind)) {
+ return indexOfNaN(array, startIndex);
+ }
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ final double min = valueToFind - tolerance;
+ final double max = valueToFind + tolerance;
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (array[i] >= min && array[i] <= max) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final float[] array, final float valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final float[] array, final float valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ final boolean searchNaN = Float.isNaN(valueToFind);
+ for (int i = max0(startIndex); i < array.length; i++) {
+ final float element = array[i];
+ if (valueToFind == element || searchNaN && Float.isNaN(element)) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final int[] array, final int valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final int[] array, final int valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final long[] array, final long valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final long[] array, final long valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given object in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return the index of the object within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final Object[] array, final Object objectToFind) {
+ return indexOf(array, objectToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given object in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @param startIndex the index to start searching.
+ * @return the index of the object within the array starting at the index, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ startIndex = max0(startIndex);
+ if (objectToFind == null) {
+ for (int i = startIndex; i < array.length; i++) {
+ if (array[i] == null) {
+ return i;
+ }
+ }
+ } else {
+ for (int i = startIndex; i < array.length; i++) {
+ if (objectToFind.equals(array[i])) {
+ return i;
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final short[] array, final short valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the index to start searching.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int indexOf(final short[] array, final short valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the NaN value in a double array.
+ * @param array the array to search for NaN, may be {@code null}.
+ * @param startIndex the index to start searching.
+ * @return the index of the NaN value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ private static int indexOfNaN(final double[] array, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (Double.isNaN(array[i])) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static boolean[] insert(final int index, final boolean[] array, final boolean... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final boolean[] result = new boolean[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static byte[] insert(final int index, final byte[] array, final byte... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final byte[] result = new byte[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static char[] insert(final int index, final char[] array, final char... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final char[] result = new char[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static double[] insert(final int index, final double[] array, final double... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final double[] result = new double[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static float[] insert(final int index, final float[] array, final float... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final float[] result = new float[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static int[] insert(final int index, final int[] array, final int... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final int[] result = new int[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static long[] insert(final int index, final long[] array, final long... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final long[] result = new long[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ public static short[] insert(final int index, final short[] array, final short... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final short[] result = new short[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
+ * When an array is returned, it is always a new array.
+ *
+ *
+ * @param The type of elements in {@code array} and {@code values}.
+ * @param index the position within {@code array} to insert the new values.
+ * @param array the array to insert the values into, may be {@code null}.
+ * @param values the new values to insert, may be {@code null}.
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided and either {@code index < 0} or {@code index > array.length}.
+ * @since 3.6
+ */
+ @SafeVarargs
+ public static T[] insert(final int index, final T[] array, final T... values) {
+ /*
+ * Note on use of @SafeVarargs:
+ *
+ * By returning null when 'array' is null, we avoid returning the vararg
+ * array to the caller. We also avoid relying on the type of the vararg
+ * array, by inspecting the component type of 'array'.
+ */
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final Class type = getComponentType(array);
+ final int length = array.length + values.length;
+ final T[] result = newInstance(type, length);
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Checks if an array is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ */
+ private static boolean isArrayEmpty(final Object array) {
+ return getLength(array) == 0;
+ }
+
+ /**
+ * Tests whether a given array can safely be accessed at the given index.
+ *
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to inspect, may be {@code null}.
+ * @param index the index of the array to be inspected.
+ * @return Whether the given index is safely-accessible in the given array.
+ * @since 3.8
+ */
+ public static boolean isArrayIndexValid(final T[] array, final int index) {
+ return index >= 0 && getLength(array) > index;
+ }
+
+ /**
+ * Tests whether an array of primitive booleans is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final boolean[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive bytes is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final byte[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive chars is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final char[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive doubles is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final double[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive floats is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final float[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive ints is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final int[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive longs is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final long[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of Objects is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final Object[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive shorts is empty or {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is empty or {@code null}.
+ * @since 2.1
+ */
+ public static boolean isEmpty(final short[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether two arrays have equal content, using equals(), handling multidimensional arrays
+ * correctly.
+ *
+ * Multi-dimensional primitive arrays are also handled correctly by this method.
+ *
+ *
+ * @param array1 the left-hand side array to compare, may be {@code null}.
+ * @param array2 the right-hand side array to compare, may be {@code null}.
+ * @return {@code true} if the arrays are equal.
+ * @deprecated Replaced by {@code java.util.Objects.deepEquals(Object, Object)} and will be
+ * removed from future releases.
+ */
+ @Deprecated
+ public static boolean isEquals(final Object array1, final Object array2) {
+ return new EqualsBuilder().append(array1, array2).isEquals();
+ }
+
+ /**
+ * Tests whether an array of primitive booleans is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final boolean[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive bytes is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final byte[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive chars is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final char[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive doubles is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final double[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive floats is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final float[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive ints is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final int[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive longs is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final long[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive shorts is not empty and not {@code null}.
+ *
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final short[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of Objects is not empty and not {@code null}.
+ *
+ * @param the component type of the array
+ * @param array the array to test.
+ * @return {@code true} if the array is not empty and not {@code null}.
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final T[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final boolean[] array1, final boolean[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final byte[] array1, final byte[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final char[] array1, final char[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final double[] array1, final double[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final float[] array1, final float[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final int[] array1, final int[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final long[] array1, final long[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * Any multi-dimensional aspects of the arrays are ignored.
+ *
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ * @since 3.11
+ */
+ public static boolean isSameLength(final Object array1, final Object array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * Any multi-dimensional aspects of the arrays are ignored.
+ *
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final Object[] array1, final Object[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}.
+ * @param array2 the second array, may be {@code null}.
+ * @return {@code true} if length of arrays matches, treating {@code null} as an empty array.
+ */
+ public static boolean isSameLength(final short[] array1, final short[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same type taking into account multidimensional arrays.
+ *
+ * @param array1 the first array, must not be {@code null}.
+ * @param array2 the second array, must not be {@code null}.
+ * @return {@code true} if type of arrays matches.
+ * @throws IllegalArgumentException if either array is {@code null}.
+ */
+ public static boolean isSameType(final Object array1, final Object array2) {
+ if (array1 == null || array2 == null) {
+ throw new IllegalArgumentException("The Array must not be null");
+ }
+ return array1.getClass().getName().equals(array2.getClass().getName());
+ }
+
+ /**
+ * Tests whether whether the provided array is sorted according to natural ordering ({@code false} before {@code true}).
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final boolean[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ boolean previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final boolean current = array[i];
+ if (BooleanUtils.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final byte[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ byte previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final byte current = array[i];
+ if (Byte.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final char[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ char previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final char current = array[i];
+ if (CharUtils.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final double[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ double previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final double current = array[i];
+ if (Double.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final float[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ float previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final float current = array[i];
+ if (Float.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final int[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ int previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final int current = array[i];
+ if (Integer.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final long[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ long previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final long current = array[i];
+ if (Long.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check.
+ * @return whether the array is sorted according to natural ordering.
+ * @since 3.4
+ */
+ public static boolean isSorted(final short[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ short previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final short current = array[i];
+ if (Short.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to the class's
+ * {@code compareTo} method.
+ *
+ * @param array the array to check.
+ * @param the datatype of the array to check, it must implement {@link Comparable}.
+ * @return whether the array is sorted.
+ * @since 3.4
+ */
+ public static > boolean isSorted(final T[] array) {
+ return isSorted(array, Comparable::compareTo);
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to the provided {@link Comparator}.
+ *
+ * @param array the array to check.
+ * @param comparator the {@link Comparator} to compare over.
+ * @param the datatype of the array.
+ * @return whether the array is sorted.
+ * @throws NullPointerException if {@code comparator} is {@code null}.
+ * @since 3.4
+ */
+ public static boolean isSorted(final T[] array, final Comparator comparator) {
+ Objects.requireNonNull(comparator, "comparator");
+ if (getLength(array) < 2) {
+ return true;
+ }
+ T previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final T current = array[i];
+ if (comparator.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) if {@code null} array input.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final boolean[] array, final boolean valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final boolean[] array, final boolean valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final byte[] array, final byte valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final byte[] array, final byte valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ * @since 2.1
+ */
+ public static int lastIndexOf(final char[] array, final char valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ * @since 2.1
+ */
+ public static int lastIndexOf(final char[] array, final char valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value within a given tolerance in the array. This method will return the index of the last value which falls between
+ * the region defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param tolerance tolerance of the search.
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, final double tolerance) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index. This method will return the index of the last value which falls between
+ * the region defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @param tolerance search for value within plus/minus this amount.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ final double min = valueToFind - tolerance;
+ final double max = valueToFind + tolerance;
+ for (int i = startIndex; i >= 0; i--) {
+ if (array[i] >= min && array[i] <= max) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final float[] array, final float valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final float[] array, final float valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final int[] array, final int valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final int[] array, final int valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final long[] array, final long valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final long[] array, final long valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given object within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return the last index of the object within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final Object[] array, final Object objectToFind) {
+ return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given object in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the object within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final Object[] array, final Object objectToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ if (objectToFind == null) {
+ for (int i = startIndex; i >= 0; i--) {
+ if (array[i] == null) {
+ return i;
+ }
+ }
+ } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
+ for (int i = startIndex; i >= 0; i--) {
+ if (objectToFind.equals(array[i])) {
+ return i;
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}.
+ * @param valueToFind the object to find.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final short[] array, final short valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}.
+ * @param valueToFind the value to find.
+ * @param startIndex the start index to traverse backwards from.
+ * @return the last index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input.
+ */
+ public static int lastIndexOf(final short[] array, final short valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Maps elements from an array into elements of a new array of a given type, while mapping old elements to new elements.
+ *
+ * @param The input array type.
+ * @param The output array type.
+ * @param The type of exceptions thrown when the mapper function fails.
+ * @param array The input array.
+ * @param componentType the component type of the result array.
+ * @param mapper a non-interfering, stateless function to apply to each element.
+ * @return a new array.
+ * @throws E Thrown when the mapper function fails.
+ */
+ private static R[] map(final T[] array, final Class componentType, final FailableFunction super T, ? extends R, E> mapper)
+ throws E {
+ return ArrayFill.fill(newInstance(componentType, array.length), i -> mapper.apply(array[i]));
+ }
+
+ private static int max0(final int other) {
+ return Math.max(0, other);
+ }
+
+ /**
+ * Delegates to {@link Array#newInstance(Class,int)} using generics.
+ *
+ * @param The array type.
+ * @param componentType The array class.
+ * @param length the array length
+ * @return The new array.
+ * @throws NullPointerException if the specified {@code componentType} parameter is null.
+ * @since 3.13.0
+ */
+ @SuppressWarnings("unchecked") // OK, because array and values are of type T
+ public static T[] newInstance(final Class componentType, final int length) {
+ return (T[]) Array.newInstance(componentType, length);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns a default array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param The array type.
+ * @param array the array to check for {@code null} or empty
+ * @param defaultArray A default array, usually empty.
+ * @return the same array, or defaultArray if {@code null} or empty input.
+ * @since 3.15.0
+ */
+ public static T[] nullTo(final T[] array, final T[] defaultArray) {
+ return isEmpty(array) ? defaultArray : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static boolean[] nullToEmpty(final boolean[] array) {
+ return isEmpty(array) ? EMPTY_BOOLEAN_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Boolean[] nullToEmpty(final Boolean[] array) {
+ return nullTo(array, EMPTY_BOOLEAN_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static byte[] nullToEmpty(final byte[] array) {
+ return isEmpty(array) ? EMPTY_BYTE_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Byte[] nullToEmpty(final Byte[] array) {
+ return nullTo(array, EMPTY_BYTE_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static char[] nullToEmpty(final char[] array) {
+ return isEmpty(array) ? EMPTY_CHAR_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Character[] nullToEmpty(final Character[] array) {
+ return nullTo(array, EMPTY_CHARACTER_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 3.2
+ */
+ public static Class>[] nullToEmpty(final Class>[] array) {
+ return nullTo(array, EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static double[] nullToEmpty(final double[] array) {
+ return isEmpty(array) ? EMPTY_DOUBLE_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Double[] nullToEmpty(final Double[] array) {
+ return nullTo(array, EMPTY_DOUBLE_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static float[] nullToEmpty(final float[] array) {
+ return isEmpty(array) ? EMPTY_FLOAT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Float[] nullToEmpty(final Float[] array) {
+ return nullTo(array, EMPTY_FLOAT_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static int[] nullToEmpty(final int[] array) {
+ return isEmpty(array) ? EMPTY_INT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Integer[] nullToEmpty(final Integer[] array) {
+ return nullTo(array, EMPTY_INTEGER_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static long[] nullToEmpty(final long[] array) {
+ return isEmpty(array) ? EMPTY_LONG_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Long[] nullToEmpty(final Long[] array) {
+ return nullTo(array, EMPTY_LONG_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Object[] nullToEmpty(final Object[] array) {
+ return nullTo(array, EMPTY_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static short[] nullToEmpty(final short[] array) {
+ return isEmpty(array) ? EMPTY_SHORT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static Short[] nullToEmpty(final Short[] array) {
+ return nullTo(array, EMPTY_SHORT_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @return the same array, {@code public static} empty array if {@code null} or empty input.
+ * @since 2.5
+ */
+ public static String[] nullToEmpty(final String[] array) {
+ return nullTo(array, EMPTY_STRING_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * @param array the array to check for {@code null} or empty.
+ * @param type the class representation of the desired array.
+ * @param the class type.
+ * @return the same array, {@code public static} empty array if {@code null}.
+ * @throws IllegalArgumentException if the type argument is null.
+ * @since 3.5
+ */
+ public static T[] nullToEmpty(final T[] array, final Class type) {
+ if (type == null) {
+ throw new IllegalArgumentException("The type must not be null");
+ }
+ if (array == null) {
+ return type.cast(Array.newInstance(type.getComponentType(), 0));
+ }
+ return array;
+ }
+
+ /**
+ * Gets the {@link ThreadLocalRandom} for {@code shuffle} methods that don't take a {@link Random} argument.
+ *
+ * @return the current ThreadLocalRandom.
+ */
+ private static ThreadLocalRandom random() {
+ return ThreadLocalRandom.current();
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static boolean[] remove(final boolean[] array, final int index) {
+ return (boolean[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static byte[] remove(final byte[] array, final int index) {
+ return (byte[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static char[] remove(final char[] array, final int index) {
+ return (char[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static double[] remove(final double[] array, final int index) {
+ return (double[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static float[] remove(final float[] array, final int index) {
+ return (float[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static int[] remove(final int[] array, final int index) {
+ return (int[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static long[] remove(final long[] array, final int index) {
+ return (long[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ private static Object remove(final Object array, final int index) {
+ final int length = getLength(array);
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+ }
+ final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
+ System.arraycopy(array, 0, result, 0, index);
+ if (index < length - 1) {
+ System.arraycopy(array, index + 1, result, index, length - index - 1);
+ }
+ return result;
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static short[] remove(final short[] array, final int index) {
+ return (short[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array. All subsequent elements are shifted to the left (subtracts one from their
+ * indices).
+ *
+ * This method returns a new array with the same elements of the input array except the element on the specified position. The component type of the
+ * returned array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param index the position of the element to be removed.
+ * @return A new array containing the existing elements except the element at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input
+ public static T[] remove(final T[] array, final int index) {
+ return (T[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static boolean[] removeAll(final boolean[] array, final int... indices) {
+ return (boolean[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static byte[] removeAll(final byte[] array, final int... indices) {
+ return (byte[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static char[] removeAll(final char[] array, final int... indices) {
+ return (char[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static double[] removeAll(final double[] array, final int... indices) {
+ return (double[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static float[] removeAll(final float[] array, final int... indices) {
+ return (float[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static int[] removeAll(final int[] array, final int... indices) {
+ return (int[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static long[] removeAll(final long[] array, final int... indices) {
+ return (long[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes multiple array elements specified by index.
+ *
+ * @param array source
+ * @param indices to remove
+ * @return new array of same type minus elements specified by unique values of {@code indices}
+ */
+ // package protected for access by unit tests
+ static Object removeAll(final Object array, final int... indices) {
+ if (array == null) {
+ return null;
+ }
+ final int length = getLength(array);
+ int diff = 0; // number of distinct indexes, i.e. number of entries that will be removed
+ final int[] clonedIndices = ArraySorter.sort(clone(indices));
+ // identify length of result array
+ if (isNotEmpty(clonedIndices)) {
+ int i = clonedIndices.length;
+ int prevIndex = length;
+ while (--i >= 0) {
+ final int index = clonedIndices[i];
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+ }
+ if (index >= prevIndex) {
+ continue;
+ }
+ diff++;
+ prevIndex = index;
+ }
+ }
+ // create result array
+ final Object result = Array.newInstance(array.getClass().getComponentType(), length - diff);
+ if (diff < length && clonedIndices != null) {
+ int end = length; // index just after last copy
+ int dest = length - diff; // number of entries so far not copied
+ for (int i = clonedIndices.length - 1; i >= 0; i--) {
+ final int index = clonedIndices[i];
+ if (end - index > 1) { // same as (cp > 0)
+ final int cp = end - index - 1;
+ dest -= cp;
+ System.arraycopy(array, index + 1, result, dest, cp);
+ // After this copy, we still have room for dest items.
+ }
+ end = index;
+ }
+ if (end > 0) {
+ System.arraycopy(array, 0, result, 0, end);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ public static short[] removeAll(final short[] array, final int... indices) {
+ return (short[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the elements at the specified positions from the specified array. All remaining elements are shifted to the left.
+ *
+ * This method returns a new array with the same elements of the input array except those at the specified positions. The component type of the returned
+ * array is always the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, then return {@code null}.
+ *
+ *
+ * @param the component type of the array.
+ * @param array the array to remove the element from, may not be {@code null}.
+ * @param indices the positions of the elements to be removed.
+ * @return A new array containing the existing elements except those at the specified positions or {@code null} if the input array is {@code null}.
+ * @throws IndexOutOfBoundsException if any index is out of range (index < 0 || index >= array.length).
+ * @since 3.0.1
+ */
+ @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input
+ public static T[] removeAll(final T[] array, final int... indices) {
+ return (T[]) removeAll((Object) array, indices);
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified boolean array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(boolean[], boolean)}.
+ */
+ @Deprecated
+ public static boolean[] removeAllOccurences(final boolean[] array, final boolean element) {
+ return (boolean[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified byte array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(byte[], byte)}.
+ */
+ @Deprecated
+ public static byte[] removeAllOccurences(final byte[] array, final byte element) {
+ return (byte[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified char array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(char[], char)}.
+ */
+ @Deprecated
+ public static char[] removeAllOccurences(final char[] array, final char element) {
+ return (char[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified double array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(double[], double)}.
+ */
+ @Deprecated
+ public static double[] removeAllOccurences(final double[] array, final double element) {
+ return (double[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified float array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(float[], float)}.
+ */
+ @Deprecated
+ public static float[] removeAllOccurences(final float[] array, final float element) {
+ return (float[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified int array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(int[], int)}.
+ */
+ @Deprecated
+ public static int[] removeAllOccurences(final int[] array, final int element) {
+ return (int[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified long array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(long[], long)}.
+ */
+ @Deprecated
+ public static long[] removeAllOccurences(final long[] array, final long element) {
+ return (long[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified short array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(short[], short)}.
+ */
+ @Deprecated
+ public static short[] removeAllOccurences(final short[] array, final short element) {
+ return (short[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param the type of object in the array, may be {@code null}.
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove, may be {@code null}.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.5
+ * @deprecated Use {@link #removeAllOccurrences(Object[], Object)}.
+ */
+ @Deprecated
+ public static T[] removeAllOccurences(final T[] array, final T element) {
+ return (T[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified boolean array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static boolean[] removeAllOccurrences(final boolean[] array, final boolean element) {
+ return (boolean[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified byte array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static byte[] removeAllOccurrences(final byte[] array, final byte element) {
+ return (byte[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified char array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static char[] removeAllOccurrences(final char[] array, final char element) {
+ return (char[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified double array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static double[] removeAllOccurrences(final double[] array, final double element) {
+ return (double[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified float array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static float[] removeAllOccurrences(final float[] array, final float element) {
+ return (float[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified int array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static int[] removeAllOccurrences(final int[] array, final int element) {
+ return (int[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified long array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static long[] removeAllOccurrences(final long[] array, final long element) {
+ return (long[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified short array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static short[] removeAllOccurrences(final short[] array, final short element) {
+ return (short[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param the type of object in the array, may be {@code null}.
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove, may be {@code null}.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static T[] removeAllOccurrences(final T[] array, final T element) {
+ return (T[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes multiple array elements specified by indices.
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param indices to remove.
+ * @return new array of same type minus elements specified by the set bits in {@code indices}.
+ */
+ // package protected for access by unit tests
+ static Object removeAt(final Object array, final BitSet indices) {
+ if (array == null) {
+ return null;
+ }
+ final int srcLength = getLength(array);
+ // No need to check maxIndex here, because method only currently called from removeElements()
+ // which guarantee to generate only valid bit entries.
+// final int maxIndex = indices.length();
+// if (maxIndex > srcLength) {
+// throw new IndexOutOfBoundsException("Index: " + (maxIndex-1) + ", Length: " + srcLength);
+// }
+ final int removals = indices.cardinality(); // true bits are items to remove
+ final Object result = Array.newInstance(array.getClass().getComponentType(), srcLength - removals);
+ int srcIndex = 0;
+ int destIndex = 0;
+ int count;
+ int set;
+ while ((set = indices.nextSetBit(srcIndex)) != -1) {
+ count = set - srcIndex;
+ if (count > 0) {
+ System.arraycopy(array, srcIndex, result, destIndex, count);
+ destIndex += count;
+ }
+ srcIndex = indices.nextClearBit(set);
+ }
+ count = srcLength - srcIndex;
+ if (count > 0) {
+ System.arraycopy(array, srcIndex, result, destIndex, count);
+ }
+ return result;
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static boolean[] removeElement(final boolean[] array, final boolean element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static byte[] removeElement(final byte[] array, final byte element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static char[] removeElement(final char[] array, final char element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static double[] removeElement(final double[] array, final double element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static float[] removeElement(final float[] array, final float element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static int[] removeElement(final int[] array, final int element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static long[] removeElement(final long[] array, final long element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static short[] removeElement(final short[] array, final short element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param the component type of the array
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed, may be {@code null}.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static T[] removeElement(final T[] array, final Object element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static boolean[] removeElements(final boolean[] array, final boolean... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(2); // only two possible values here
+ for (final boolean v : values) {
+ increment(occurrences, Boolean.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final boolean key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (boolean[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static byte[] removeElements(final byte[] array, final byte... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final byte v : values) {
+ increment(occurrences, Byte.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final byte key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (byte[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static char[] removeElements(final char[] array, final char... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final char v : values) {
+ increment(occurrences, Character.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final char key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (char[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static double[] removeElements(final double[] array, final double... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final double v : values) {
+ increment(occurrences, Double.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final double key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (double[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static float[] removeElements(final float[] array, final float... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final float v : values) {
+ increment(occurrences, Float.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final float key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (float[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static int[] removeElements(final int[] array, final int... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final int v : values) {
+ increment(occurrences, Integer.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final int key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (int[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static long[] removeElements(final long[] array, final long... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final long v : values) {
+ increment(occurrences, Long.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final long key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (long[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ public static short[] removeElements(final short[] array, final short... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final short v : values) {
+ increment(occurrences, Short.valueOf(v));
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final short key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ return (short[]) removeAt(array, toRemove);
+ }
+
+ /**
+ * Removes occurrences of specified elements, in specified quantities,
+ * from the specified array. All subsequent elements are shifted left.
+ * For any element-to-be-removed specified in greater quantities than
+ * contained in the original array, no change occurs beyond the
+ * removal of the existing matching items.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except for the earliest-encountered occurrences of the specified
+ * elements. The component type of the returned array is always the same
+ * as that of the input array.
+ *
+ *
+ * @param the component type of the array
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param values the values to be removed.
+ * @return A new array containing the existing elements except the
+ * earliest-encountered occurrences of the specified elements.
+ * @since 3.0.1
+ */
+ @SafeVarargs
+ public static T[] removeElements(final T[] array, final T... values) {
+ if (isEmpty(array) || isEmpty(values)) {
+ return clone(array);
+ }
+ final HashMap occurrences = new HashMap<>(values.length);
+ for (final T v : values) {
+ increment(occurrences, v);
+ }
+ final BitSet toRemove = new BitSet();
+ for (int i = 0; i < array.length; i++) {
+ final T key = array[i];
+ final MutableInt count = occurrences.get(key);
+ if (count != null) {
+ if (count.decrementAndGet() == 0) {
+ occurrences.remove(key);
+ }
+ toRemove.set(i);
+ }
+ }
+ @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input
+ final T[] result = (T[]) removeAt(array, toRemove);
+ return result;
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final boolean[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ boolean tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final byte[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no change.
+ * @param endIndexExclusive elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no change. Overvalue
+ * (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ byte tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final char[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no change.
+ * @param endIndexExclusive elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no change. Overvalue
+ * (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ char tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}
+ */
+ public static void reverse(final double[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no change.
+ * @param endIndexExclusive elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no change. Overvalue
+ * (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ double tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final float[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no change.
+ * @param endIndexExclusive elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no change. Overvalue
+ * (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ float tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final int[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ int tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final long[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ long tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * There is no special handling for multi-dimensional arrays.
+ *
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final Object[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Under value (<0) is promoted to 0, over value (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Under value (< start index) results in no
+ * change. Over value (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final Object[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ Object tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final short[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ short tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Sets all elements of the specified array, using the provided generator supplier to compute each element.
+ *
+ * If the generator supplier throws an exception, it is relayed to the caller and the array is left in an indeterminate
+ * state.
+ *
+ *
+ * @param type of elements of the array, may be {@code null}.
+ * @param array array to be initialized, may be {@code null}.
+ * @param generator a function accepting an index and producing the desired value for that position.
+ * @return the input array
+ * @since 3.13.0
+ */
+ public static T[] setAll(final T[] array, final IntFunction extends T> generator) {
+ if (array != null && generator != null) {
+ Arrays.setAll(array, generator);
+ }
+ return array;
+ }
+
+ /**
+ * Sets all elements of the specified array, using the provided generator supplier to compute each element.
+ *
+ * If the generator supplier throws an exception, it is relayed to the caller and the array is left in an indeterminate
+ * state.
+ *
+ *
+ * @param type of elements of the array, may be {@code null}.
+ * @param array array to be initialized, may be {@code null}.
+ * @param generator a function accepting an index and producing the desired value for that position.
+ * @return the input array
+ * @since 3.13.0
+ */
+ public static T[] setAll(final T[] array, final Supplier extends T> generator) {
+ if (array != null && generator != null) {
+ for (int i = 0; i < array.length; i++) {
+ array[i] = generator.get();
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Shifts the order of the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final boolean[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final boolean[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final byte[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final byte[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final char[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final char[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final double[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final double[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final float[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final float[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final int[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final int[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final long[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final long[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final Object[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final Object[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final short[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final short[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final boolean[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final boolean[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final byte[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final byte[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final char[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final char[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final double[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final double[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final float[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final float[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final int[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final int[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final long[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final long[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final Object[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final Object[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final short[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle, no-op if {@code null}.
+ * @param random the source of randomness used to permute the elements, no-op if {@code null}.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final short[] array, final Random random) {
+ if (array != null && random != null) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+ }
+
+ /**
+ * Tests whether the given data array starts with an expected array, for example, signature bytes.
+ *
+ * If both arrays are null, the method returns true. The method return false when one array is null and the other not.
+ *
+ *
+ * @param data The data to search, maybe larger than the expected data.
+ * @param expected The expected data to find.
+ * @return whether a match was found.
+ * @since 3.18.0
+ */
+ public static boolean startsWith(final byte[] data, final byte[] expected) {
+ if (data == expected) {
+ return true;
+ }
+ if (data == null || expected == null) {
+ return false;
+ }
+ final int dataLen = data.length;
+ if (expected.length > dataLen) {
+ return false;
+ }
+ if (expected.length == dataLen) {
+ // delegate to Arrays.equals() which has optimizations on Java > 8
+ return Arrays.equals(data, expected);
+ }
+ // Once we are on Java 9+ we can delegate to Arrays here as well (or not).
+ for (int i = 0; i < expected.length; i++) {
+ if (data[i] != expected[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Produces a new {@code boolean} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(boolean[], int, int)
+ */
+ public static boolean[] subarray(final boolean[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_BOOLEAN_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, boolean[]::new);
+ }
+
+ /**
+ * Produces a new {@code byte} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(byte[], int, int)
+ */
+ public static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, byte[]::new);
+ }
+
+ /**
+ * Produces a new {@code char} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(char[], int, int)
+ */
+ public static char[] subarray(final char[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_CHAR_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, char[]::new);
+ }
+
+ /**
+ * Produces a new {@code double} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(double[], int, int)
+ */
+ public static double[] subarray(final double[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_DOUBLE_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, double[]::new);
+ }
+
+ /**
+ * Produces a new {@code float} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(float[], int, int)
+ */
+ public static float[] subarray(final float[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_FLOAT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, float[]::new);
+ }
+
+ /**
+ * Produces a new {@code int} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(int[], int, int)
+ */
+ public static int[] subarray(final int[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_INT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, int[]::new);
+ }
+
+ /**
+ * Produces a new {@code long} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(long[], int, int)
+ */
+ public static long[] subarray(final long[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_LONG_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, long[]::new);
+ }
+
+ /**
+ * Produces a new {@code short} array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(short[], int, int)
+ */
+ public static short[] subarray(final short[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_SHORT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, short[]::new);
+ }
+
+ /**
+ * Produces a new array containing the elements between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive. Null array input produces null output.
+ *
+ *
+ * The component type of the subarray is always the same as that of the input array. Thus, if the input is an array of type {@link Date}, the following
+ * usage is envisaged:
+ *
+ *
+ * @param the component type of the array.
+ * @param array the input array.
+ * @param startIndexInclusive the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the returned subarray. Undervalue (< startIndex) produces empty array, overvalue
+ * (>array.length) is demoted to array length.
+ * @return a new array containing the elements between the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(Object[], int, int)
+ */
+ public static T[] subarray(final T[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = max0(Math.min(endIndexExclusive, array.length));
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ final Class type = getComponentType(array);
+ if (newSize <= 0) {
+ return newInstance(type, 0);
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, () -> newInstance(type, newSize));
+ }
+
+ /**
+ * Swaps two elements in the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final boolean[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given boolean array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final boolean[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final boolean aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final byte[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given byte array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final byte[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final byte aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final char[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given char array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final char[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final char aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final double[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given double array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final double[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final double aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final float[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given float array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final float[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final float aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+
+ }
+
+ /**
+ * Swaps two elements in the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final int[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given int array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final int[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final int aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final long[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given long array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final long[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final long aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final Object[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final Object[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final Object aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap.
+ * @param offset2 the index of the second element to swap.
+ * @since 3.5
+ */
+ public static void swap(final short[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given short array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap.
+ * @param offset2 the index of the second element in the series to swap.
+ * @param len the number of elements to swap starting with the given indices.
+ * @since 3.5
+ */
+ public static void swap(final short[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ if (offset1 == offset2) {
+ return;
+ }
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final short aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Create a type-safe generic array.
+ *
+ * The Java language does not allow an array to be created from a generic type:
+ *
+ *
+ public static <T> T[] createAnArray(int size) {
+ return new T[size]; // compiler error here
+ }
+ public static <T> T[] createAnArray(int size) {
+ return (T[]) new Object[size]; // ClassCastException at runtime
+ }
+ *
+ *
+ * Therefore new arrays of generic types can be created with this method.
+ * For example, an array of Strings can be created:
+ *
+ * The method is typically used in scenarios, where the caller itself uses generic types
+ * that have to be combined into an array.
+ *
+ *
+ * Note, this method makes only sense to provide arguments of the same type so that the
+ * compiler can deduce the type of the array itself. While it is possible to select the
+ * type explicitly like in
+ * {@code Number[] array = ArrayUtils.toArray(Integer.valueOf(42), Double.valueOf(Math.PI))},
+ * there is no real advantage when compared to
+ * {@code new Number[] {Integer.valueOf(42), Double.valueOf(Math.PI)}}.
+ *
+ *
+ * @param the array's element type.
+ * @param items the varargs array items, null allowed.
+ * @return the array, not null unless a null array is passed in.
+ * @since 3.0
+ */
+ public static T[] toArray(@SuppressWarnings("unchecked") final T... items) {
+ return items;
+ }
+
+ /**
+ * Converts the given array into a {@link java.util.Map}. Each element of the array must be either a {@link java.util.Map.Entry} or an Array, containing at
+ * least two elements, where the first element is used as key and the second as value.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array an array whose elements are either a {@link java.util.Map.Entry} or an Array containing at least two elements, may be {@code null}.
+ * @return a {@link Map} that was created from the array.
+ * @throws IllegalArgumentException if one element of this Array is itself an Array containing less than two elements.
+ * @throws IllegalArgumentException if the array contains elements other than {@link java.util.Map.Entry} and an Array.
+ */
+ public static Map toMap(final Object[] array) {
+ if (array == null) {
+ return null;
+ }
+ final Map map = new HashMap<>((int) (array.length * 1.5));
+ for (int i = 0; i < array.length; i++) {
+ final Object object = array[i];
+ if (object instanceof Map.Entry, ?>) {
+ final Map.Entry, ?> entry = (Map.Entry, ?>) object;
+ map.put(entry.getKey(), entry.getValue());
+ } else if (object instanceof Object[]) {
+ final Object[] entry = (Object[]) object;
+ if (entry.length < 2) {
+ throw new IllegalArgumentException("Array element " + i + ", '"
+ + object
+ + "', has a length less than 2");
+ }
+ map.put(entry[0], entry[1]);
+ } else {
+ throw new IllegalArgumentException("Array element " + i + ", '"
+ + object
+ + "', is neither of type Map.Entry nor an Array");
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Converts an array of primitive booleans to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code boolean} array.
+ * @return a {@link Boolean} array, {@code null} if null array input.
+ */
+ public static Boolean[] toObject(final boolean[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_BOOLEAN_OBJECT_ARRAY;
+ }
+ return setAll(new Boolean[array.length], i -> array[i] ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ /**
+ * Converts an array of primitive bytes to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code byte} array.
+ * @return a {@link Byte} array, {@code null} if null array input.
+ */
+ public static Byte[] toObject(final byte[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_BYTE_OBJECT_ARRAY;
+ }
+ return setAll(new Byte[array.length], i -> Byte.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive chars to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code char} array.
+ * @return a {@link Character} array, {@code null} if null array input.
+ */
+ public static Character[] toObject(final char[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_CHARACTER_OBJECT_ARRAY;
+ }
+ return setAll(new Character[array.length], i -> Character.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive doubles to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code double} array.
+ * @return a {@link Double} array, {@code null} if null array input.
+ */
+ public static Double[] toObject(final double[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_DOUBLE_OBJECT_ARRAY;
+ }
+ return setAll(new Double[array.length], i -> Double.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive floats to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code float} array.
+ * @return a {@link Float} array, {@code null} if null array input.
+ */
+ public static Float[] toObject(final float[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_FLOAT_OBJECT_ARRAY;
+ }
+ return setAll(new Float[array.length], i -> Float.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive ints to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array an {@code int} array.
+ * @return an {@link Integer} array, {@code null} if null array input.
+ */
+ public static Integer[] toObject(final int[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_INTEGER_OBJECT_ARRAY;
+ }
+ return setAll(new Integer[array.length], i -> Integer.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive longs to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code long} array.
+ * @return a {@link Long} array, {@code null} if null array input.
+ */
+ public static Long[] toObject(final long[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_LONG_OBJECT_ARRAY;
+ }
+ return setAll(new Long[array.length], i -> Long.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of primitive shorts to objects.
+ *
+ *
This method returns {@code null} for a {@code null} input array.
+ *
+ * @param array a {@code short} array.
+ * @return a {@link Short} array, {@code null} if null array input.
+ */
+ public static Short[] toObject(final short[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_SHORT_OBJECT_ARRAY;
+ }
+ return setAll(new Short[array.length], i -> Short.valueOf(array[i]));
+ }
+
+ /**
+ * Converts an array of object Booleans to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * Null array elements map to false, like {@code Boolean.parseBoolean(null)} and its callers return false.
+ *
+ *
+ * @param array a {@link Boolean} array, may be {@code null}.
+ * @return a {@code boolean} array, {@code null} if null array input.
+ */
+ public static boolean[] toPrimitive(final Boolean[] array) {
+ return toPrimitive(array, false);
+ }
+
+ /**
+ * Converts an array of object Booleans to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Boolean} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code boolean} array, {@code null} if null array input.
+ */
+ public static boolean[] toPrimitive(final Boolean[] array, final boolean valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_BOOLEAN_ARRAY;
+ }
+ final boolean[] result = new boolean[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Boolean b = array[i];
+ result[i] = b == null ? valueForNull : b.booleanValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Bytes to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Byte} array, may be {@code null}.
+ * @return a {@code byte} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static byte[] toPrimitive(final Byte[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ final byte[] result = new byte[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].byteValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Bytes to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Byte} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code byte} array, {@code null} if null array input.
+ */
+ public static byte[] toPrimitive(final Byte[] array, final byte valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ final byte[] result = new byte[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Byte b = array[i];
+ result[i] = b == null ? valueForNull : b.byteValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Characters to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Character} array, may be {@code null}.
+ * @return a {@code char} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static char[] toPrimitive(final Character[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_CHAR_ARRAY;
+ }
+ final char[] result = new char[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].charValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Character to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Character} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code char} array, {@code null} if null array input.
+ */
+ public static char[] toPrimitive(final Character[] array, final char valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_CHAR_ARRAY;
+ }
+ final char[] result = new char[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Character b = array[i];
+ result[i] = b == null ? valueForNull : b.charValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Doubles to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Double} array, may be {@code null}.
+ * @return a {@code double} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static double[] toPrimitive(final Double[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_DOUBLE_ARRAY;
+ }
+ final double[] result = new double[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].doubleValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Doubles to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Double} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code double} array, {@code null} if null array input.
+ */
+ public static double[] toPrimitive(final Double[] array, final double valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_DOUBLE_ARRAY;
+ }
+ final double[] result = new double[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Double b = array[i];
+ result[i] = b == null ? valueForNull : b.doubleValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Floats to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Float} array, may be {@code null}.
+ * @return a {@code float} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static float[] toPrimitive(final Float[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_FLOAT_ARRAY;
+ }
+ final float[] result = new float[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].floatValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Floats to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Float} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code float} array, {@code null} if null array input.
+ */
+ public static float[] toPrimitive(final Float[] array, final float valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_FLOAT_ARRAY;
+ }
+ final float[] result = new float[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Float b = array[i];
+ result[i] = b == null ? valueForNull : b.floatValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Integers to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Integer} array, may be {@code null}.
+ * @return an {@code int} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static int[] toPrimitive(final Integer[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_INT_ARRAY;
+ }
+ final int[] result = new int[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Integer to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Integer} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return an {@code int} array, {@code null} if null array input.
+ */
+ public static int[] toPrimitive(final Integer[] array, final int valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_INT_ARRAY;
+ }
+ final int[] result = new int[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Integer b = array[i];
+ result[i] = b == null ? valueForNull : b.intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Longs to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Long} array, may be {@code null}.
+ * @return a {@code long} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static long[] toPrimitive(final Long[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_LONG_ARRAY;
+ }
+ final long[] result = new long[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].longValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Long to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Long} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code long} array, {@code null} if null array input.
+ */
+ public static long[] toPrimitive(final Long[] array, final long valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_LONG_ARRAY;
+ }
+ final long[] result = new long[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Long b = array[i];
+ result[i] = b == null ? valueForNull : b.longValue();
+ }
+ return result;
+ }
+
+ /**
+ * Create an array of primitive type from an array of wrapper types.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array an array of wrapper object.
+ * @return an array of the corresponding primitive type, or the original array.
+ * @since 3.5
+ */
+ public static Object toPrimitive(final Object array) {
+ if (array == null) {
+ return null;
+ }
+ final Class> ct = array.getClass().getComponentType();
+ final Class> pt = ClassUtils.wrapperToPrimitive(ct);
+ if (Boolean.TYPE.equals(pt)) {
+ return toPrimitive((Boolean[]) array);
+ }
+ if (Character.TYPE.equals(pt)) {
+ return toPrimitive((Character[]) array);
+ }
+ if (Byte.TYPE.equals(pt)) {
+ return toPrimitive((Byte[]) array);
+ }
+ if (Integer.TYPE.equals(pt)) {
+ return toPrimitive((Integer[]) array);
+ }
+ if (Long.TYPE.equals(pt)) {
+ return toPrimitive((Long[]) array);
+ }
+ if (Short.TYPE.equals(pt)) {
+ return toPrimitive((Short[]) array);
+ }
+ if (Double.TYPE.equals(pt)) {
+ return toPrimitive((Double[]) array);
+ }
+ if (Float.TYPE.equals(pt)) {
+ return toPrimitive((Float[]) array);
+ }
+ return array;
+ }
+
+ /**
+ * Converts an array of object Shorts to primitives.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Short} array, may be {@code null}.
+ * @return a {@code byte} array, {@code null} if null array input.
+ * @throws NullPointerException if an array element is {@code null}.
+ */
+ public static short[] toPrimitive(final Short[] array) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_SHORT_ARRAY;
+ }
+ final short[] result = new short[array.length];
+ for (int i = 0; i < array.length; i++) {
+ result[i] = array[i].shortValue();
+ }
+ return result;
+ }
+
+ /**
+ * Converts an array of object Short to primitives handling {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array a {@link Short} array, may be {@code null}.
+ * @param valueForNull the value to insert if {@code null} found.
+ * @return a {@code byte} array, {@code null} if null array input.
+ */
+ public static short[] toPrimitive(final Short[] array, final short valueForNull) {
+ if (array == null) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_SHORT_ARRAY;
+ }
+ final short[] result = new short[array.length];
+ for (int i = 0; i < array.length; i++) {
+ final Short b = array[i];
+ result[i] = b == null ? valueForNull : b.shortValue();
+ }
+ return result;
+ }
+
+ /**
+ * Outputs an array as a String, treating {@code null} as an empty array.
+ *
+ * Multi-dimensional arrays are handled correctly, including
+ * multi-dimensional primitive arrays.
+ *
+ *
+ * The format is that of Java source code, for example {@code {a,b}}.
+ *
+ *
+ * @param array the array to get a toString for, may be {@code null}.
+ * @return a String representation of the array, '{}' if null array input.
+ */
+ public static String toString(final Object array) {
+ return toString(array, "{}");
+ }
+
+ /**
+ * Outputs an array as a String handling {@code null}s.
+ *
+ * Multi-dimensional arrays are handled correctly, including
+ * multi-dimensional primitive arrays.
+ *
+ *
+ * The format is that of Java source code, for example {@code {a,b}}.
+ *
+ *
+ * @param array the array to get a toString for, may be {@code null}.
+ * @param stringIfNull the String to return if the array is {@code null}.
+ * @return a String representation of the array.
+ */
+ public static String toString(final Object array, final String stringIfNull) {
+ return array != null ? new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString() : stringIfNull;
+ }
+
+ /**
+ * Returns an array containing the string representation of each element in the argument array.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the {@code Object[]} to be processed, may be {@code null}.
+ * @return {@code String[]} of the same size as the source with its element's string representation, {@code null} if null array input.
+ * @since 3.6
+ */
+ public static String[] toStringArray(final Object[] array) {
+ return toStringArray(array, "null");
+ }
+
+ /**
+ * Returns an array containing the string representation of each element in the argument array handling {@code null} elements.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the Object[] to be processed, may be {@code null}.
+ * @param valueForNullElements the value to insert if {@code null} is found.
+ * @return a {@link String} array, {@code null} if null array input.
+ * @since 3.6
+ */
+ public static String[] toStringArray(final Object[] array, final String valueForNullElements) {
+ if (null == array) {
+ return null;
+ }
+ if (array.length == 0) {
+ return EMPTY_STRING_ARRAY;
+ }
+ return map(array, String.class, e -> Objects.toString(e, valueForNullElements));
+ }
+
+ /**
+ * ArrayUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ArrayUtils.clone(new int[] {2})}.
+ *
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ *
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public ArrayUtils() {
+ // empty
+ }
+}
diff --git a/src/main/java/org/apache/commons/lang3/BitField.java b/src/main/java/org/apache/commons/lang3/BitField.java
index 824d242123d..d8412021884 100644
--- a/src/main/java/org/apache/commons/lang3/BitField.java
+++ b/src/main/java/org/apache/commons/lang3/BitField.java
@@ -5,327 +5,392 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package org.apache.commons.lang3;
/**
- *
Supports operations on bit-mapped fields. Instances of this class can be
- * used to store a flag or data within an {@code int}, {@code short} or
- * {@code byte}.
- *
- *
Each {@code BitField} is constructed with a mask value, which indicates
- * the bits that will be used to store and retrieve the data for that field.
- * For instance, the mask {@code 0xFF} indicates the least-significant byte
- * should be used to store the data.
- *
- *
As an example, consider a car painting machine that accepts
- * paint instructions as integers. Bit fields can be used to encode this:
+ * Supports operations on bit-mapped fields. Instances of this class can be used to store a flag or data within an {@code int}, {@code short} or {@code byte}.
+ *
+ * Each {@link BitField} is constructed with a mask value, which indicates the bits that will be used to store and retrieve the data for that field. For
+ * instance, the mask {@code 0xFF} indicates the least-significant byte should be used to store the data.
+ *
+ *
+ * As an example, consider a car painting machine that accepts paint instructions as integers. Bit fields can be used to encode this:
+ *
+ *
+ *
+ *
+ * // blue, green and red are 1 byte values (0-255) stored in the three least
+ * // significant bytes
+ * BitField blue = new BitField(0xFF);
+ *
+ * BitField green = new BitField(0xFF00);
+ *
+ * BitField red = new BitField(0xFF0000);
*
- *
- * // blue, green and red are 1 byte values (0-255) stored in the three least
- * // significant bytes
- * BitField blue = new BitField(0xFF);
- * BitField green = new BitField(0xFF00);
- * BitField red = new BitField(0xFF0000);
- *
- * // anyColor is a flag triggered if any color is used
- * BitField anyColor = new BitField(0xFFFFFF);
- *
- * // isMetallic is a single bit flag
- * BitField isMetallic = new BitField(0x1000000);
- *
+ * // anyColor is a flag triggered if any color is used
+ * BitField anyColor = new BitField(0xFFFFFF);
*
- *
Using these {@code BitField} instances, a paint instruction can be
- * encoded into an integer:
+ * // isMetallic is a single bit flag
+ * BitField isMetallic = new BitField(0x1000000);
+ *
+ *
+ * Using these {@link BitField} instances, a paint instruction can be encoded into an integer:
+ *
+ * Flags and data can be retrieved from the integer:
+ *
*
- *
Flags and data can be retrieved from the integer:
- *
- *
- * // Prints true if red, green or blue is non-zero
- * System.out.println(anyColor.isSet(paintInstruction)); // prints true
- *
- * // Prints value of red, green and blue
- * System.out.println(red.getValue(paintInstruction)); // prints 35
- * System.out.println(green.getValue(paintInstruction)); // prints 100
- * System.out.println(blue.getValue(paintInstruction)); // prints 255
- *
- * // Prints true if isMetallic was set
- * System.out.println(isMetallic.isSet(paintInstruction)); // prints false
- *
+ *
+ * // Prints true if red, green or blue is non-zero
+ * System.out.println(anyColor.isSet(paintInstruction)); // prints true
+ * // Prints value of red, green and blue
+ * System.out.println(red.getValue(paintInstruction)); // prints 35
+ * System.out.println(green.getValue(paintInstruction)); // prints 100
+ * System.out.println(blue.getValue(paintInstruction)); // prints 255
+ * // Prints true if isMetallic was set
+ * System.out.println(isMetallic.isSet(paintInstruction)); // prints false
+ *
*
* @since 2.0
*/
public class BitField {
-
- private final int _mask;
- private final int _shift_count;
+
+ private final long mask;
+
+ private final int shiftCount;
/**
- *
Creates a BitField instance.
+ * Creates a BitField instance.
*
- * @param mask the mask specifying which bits apply to this
- * BitField. Bits that are set in this mask are the bits
- * that this BitField operates on
+ * @param mask the mask specifying which bits apply to this BitField. Bits that are set in this mask are the bits that this BitField operates on.
*/
public BitField(final int mask) {
- _mask = mask;
- int count = 0;
- int bit_pattern = mask;
+ this.mask = mask;
+ this.shiftCount = mask == 0 ? 0 : Integer.numberOfTrailingZeros(mask);
+ }
- if (bit_pattern != 0) {
- while ((bit_pattern & 1) == 0) {
- count++;
- bit_pattern >>= 1;
- }
- }
- _shift_count = count;
+ /**
+ * Creates a BitField instance.
+ *
+ * @param mask the mask specifying which bits apply to this BitField. Bits that are set in this mask are the bits that this BitField operates on.
+ * @since 3.21.0
+ */
+ public BitField(final long mask) {
+ this.mask = mask;
+ this.shiftCount = mask == 0 ? 0 : Long.numberOfTrailingZeros(mask);
}
/**
- *
Obtains the value for the specified BitField, appropriately
- * shifted right.
+ * Clears the bits.
*
- *
Many users of a BitField will want to treat the specified
- * bits as an int value, and will not want to be aware that the
- * value is stored as a BitField (and so shifted left so many
- * bits).
+ * @param holder the int data containing the bits we're interested in.
+ * @return the value of holder with the specified bits cleared (set to {@code 0}).
+ */
+ public int clear(final int holder) {
+ return (int) (holder & ~mask);
+ }
+
+ /**
+ * Clears the bits.
*
- * @see #setValue(int,int)
- * @param holder the int data containing the bits we're interested
- * in
- * @return the selected bits, shifted right appropriately
+ * @param holder the long data containing the bits we're interested in.
+ * @return the value of holder with the specified bits cleared (set to {@code 0}).
+ * @since 3.21.0
*/
- public int getValue(final int holder) {
- return getRawValue(holder) >> _shift_count;
+ public long clear(final long holder) {
+ return holder & ~mask;
}
/**
- *
Obtains the value for the specified BitField, appropriately
- * shifted right, as a short.
+ * Clears the bits.
*
- *
Many users of a BitField will want to treat the specified
- * bits as an int value, and will not want to be aware that the
- * value is stored as a BitField (and so shifted left so many
- * bits).
+ * @param holder the byte data containing the bits we're interested in.
+ * @return the value of holder with the specified bits cleared (set to {@code 0}).
+ */
+ public byte clearByte(final byte holder) {
+ return (byte) clear(holder);
+ }
+
+ /**
+ * Clears the bits.
*
- * @see #setShortValue(short,short)
- * @param holder the short data containing the bits we're
- * interested in
- * @return the selected bits, shifted right appropriately
+ * @param holder the short data containing the bits we're interested in.
+ * @return the value of holder with the specified bits cleared (set to {@code 0}).
*/
- public short getShortValue(final short holder) {
- return (short) getValue(holder);
+ public short clearShort(final short holder) {
+ return (short) clear(holder);
}
/**
- *
Obtains the value for the specified BitField, unshifted.
+ * Gets the value for the specified BitField, unshifted.
*
- * @param holder the int data containing the bits we're
- * interested in
- * @return the selected bits
+ * @param holder the int data containing the bits we're interested in.
+ * @return the selected bits.
*/
public int getRawValue(final int holder) {
- return holder & _mask;
+ return (int) (holder & mask);
}
/**
- *
Obtains the value for the specified BitField, unshifted.
+ * Gets the value for the specified BitField, unshifted.
*
- * @param holder the short data containing the bits we're
- * interested in
- * @return the selected bits
+ * @param holder the long data containing the bits we're interested in.
+ * @return the selected bits.
+ * @since 3.21.0
+ */
+ public long getRawValue(final long holder) {
+ return holder & mask;
+ }
+
+ /**
+ * Obtains the value for the specified BitField, unshifted.
+ *
+ * @param holder the short data containing the bits we're interested in.
+ * @return the selected bits.
*/
public short getShortRawValue(final short holder) {
return (short) getRawValue(holder);
}
/**
- *
Returns whether the field is set or not.
+ * Gets the value for the specified BitField, appropriately shifted right, as a short.
+ *
+ * Many users of a BitField will want to treat the specified bits as an int value, and will not want to be aware that the value is stored as a BitField (and
+ * so shifted left so many bits).
+ *
*
- *
This is most commonly used for a single-bit field, which is
- * often used to represent a boolean value; the results of using
- * it for a multi-bit field is to determine whether *any* of its
- * bits are set.
+ * @param holder the short data containing the bits we're interested in.
+ * @return the selected bits, shifted right appropriately.
+ * @see #setShortValue(short,short)
+ */
+ public short getShortValue(final short holder) {
+ return (short) getValue(holder);
+ }
+
+ /**
+ * Gets the value for the specified BitField, appropriately shifted right.
+ *
+ * Many users of a BitField will want to treat the specified bits as an int value, and will not want to be aware that the value is stored as a BitField (and
+ * so shifted left so many bits).
+ *
*
- * @param holder the int data containing the bits we're interested
- * in
- * @return {@code true} if any of the bits are set,
- * else {@code false}
+ * @param holder the int data containing the bits we're interested in.
+ * @return the selected bits, shifted right appropriately.
+ * @see #setValue(int,int)
*/
- public boolean isSet(final int holder) {
- return (holder & _mask) != 0;
+ public int getValue(final int holder) {
+ return getRawValue(holder) >> shiftCount;
}
/**
- *
Returns whether all of the bits are set or not.
+ * Gets the value for the specified BitField, appropriately shifted right.
+ *
+ * Many users of a BitField will want to treat the specified bits as an long value, and will not want to be aware that the value is stored as a BitField (and
+ * so shifted left so many bits).
+ *
*
- *
This is a stricter test than {@link #isSet(int)},
- * in that all of the bits in a multi-bit set must be set
- * for this method to return {@code true}.
+ * @param holder the long data containing the bits we're interested in.
+ * @return the selected bits, shifted right appropriately.
+ * @see #setValue(long,long)
+ * @since 3.21.0
+ */
+ public long getValue(final long holder) {
+ return getRawValue(holder) >> shiftCount;
+ }
+
+ /**
+ * Tests whether all of the bits are set or not.
+ *
+ * This is a stricter test than {@link #isSet(int)}, in that all of the bits in a multi-bit set must be set for this method to return {@code true}.
+ *
*
- * @param holder the int data containing the bits we're
- * interested in
- * @return {@code true} if all of the bits are set,
- * else {@code false}
+ * @param holder the int data containing the bits we're interested in.
+ * @return {@code true} if all of the bits are set, else {@code false}.
*/
public boolean isAllSet(final int holder) {
- return (holder & _mask) == _mask;
+ return (holder & mask) == mask;
}
/**
- *
Replaces the bits with new values.
+ * Tests whether all of the bits are set or not.
+ *
+ * This is a stricter test than {@link #isSet(long)}, in that all of the bits in a multi-bit set must be set for this method to return {@code true}.
+ *
*
- * @see #getValue(int)
- * @param holder the int data containing the bits we're
- * interested in
- * @param value the new value for the specified bits
- * @return the value of holder with the bits from the value
- * parameter replacing the old bits
+ * @param holder the long data containing the bits we're interested in.
+ * @return {@code true} if all of the bits are set, else {@code false}.
+ * @since 3.21.0
*/
- public int setValue(final int holder, final int value) {
- return (holder & ~_mask) | ((value << _shift_count) & _mask);
+ public boolean isAllSet(final long holder) {
+ return (holder & mask) == mask;
}
/**
- *
Replaces the bits with new values.
+ * Tests whether the field is set or not.
+ *
+ * This is most commonly used for a single-bit field, which is often used to represent a boolean value; the results of using it for a multi-bit field is to
+ * determine whether any of its bits are set.
+ *
*
- * @see #getShortValue(short)
- * @param holder the short data containing the bits we're
- * interested in
- * @param value the new value for the specified bits
- * @return the value of holder with the bits from the value
- * parameter replacing the old bits
+ * @param holder the int data containing the bits we're interested in
+ * @return {@code true} if any of the bits are set, else {@code false}
*/
- public short setShortValue(final short holder, final short value) {
- return (short) setValue(holder, value);
+ public boolean isSet(final int holder) {
+ return (holder & mask) != 0;
}
/**
- *
Clears the bits.
+ * Tests whether the field is set or not.
+ *
+ * This is most commonly used for a single-bit field, which is often used to represent a boolean value; the results of using it for a multi-bit field is to
+ * determine whether any of its bits are set.
+ *
*
- * @param holder the int data containing the bits we're
- * interested in
- * @return the value of holder with the specified bits cleared
- * (set to {@code 0})
+ * @param holder the long data containing the bits we're interested in
+ * @return {@code true} if any of the bits are set, else {@code false}
+ * @since 3.21.0
*/
- public int clear(final int holder) {
- return holder & ~_mask;
+ public boolean isSet(final long holder) {
+ return (holder & mask) != 0;
}
/**
- *
Clears the bits.
+ * Sets the bits.
*
- * @param holder the short data containing the bits we're
- * interested in
- * @return the value of holder with the specified bits cleared
- * (set to {@code 0})
+ * @param holder the int data containing the bits we're interested in.
+ * @return the value of holder with the specified bits set to {@code 1}.
*/
- public short clearShort(final short holder) {
- return (short) clear(holder);
+ public int set(final int holder) {
+ return (int) (holder | mask);
}
/**
- *
Clears the bits.
- *
- * @param holder the byte data containing the bits we're
- * interested in
+ * Sets the bits.
*
- * @return the value of holder with the specified bits cleared
- * (set to {@code 0})
+ * @param holder the long data containing the bits we're interested in.
+ * @return the value of holder with the specified bits set to {@code 1}.
+ * @since 3.21.0
*/
- public byte clearByte(final byte holder) {
- return (byte) clear(holder);
+ public long set(final long holder) {
+ return holder | mask;
}
/**
- *
Sets the bits.
+ * Sets a boolean BitField.
*
- * @param holder the int data containing the bits we're
- * interested in
- * @return the value of holder with the specified bits set
- * to {@code 1}
+ * @param holder the int data containing the bits we're interested in.
+ * @param flag indicating whether to set or clear the bits.
+ * @return the value of holder with the specified bits set or cleared.
*/
- public int set(final int holder) {
- return holder | _mask;
+ public int setBoolean(final int holder, final boolean flag) {
+ return flag ? set(holder) : clear(holder);
}
/**
- *
Sets the bits.
+ * Sets a boolean BitField.
*
- * @param holder the short data containing the bits we're
- * interested in
- * @return the value of holder with the specified bits set
- * to {@code 1}
+ * @param holder the long data containing the bits we're interested in.
+ * @param flag indicating whether to set or clear the bits.
+ * @return the value of holder with the specified bits set or cleared.
+ * @since 3.21.0
*/
- public short setShort(final short holder) {
- return (short) set(holder);
+ public long setBoolean(final long holder, final boolean flag) {
+ return flag ? set(holder) : clear(holder);
}
/**
- *
Sets the bits.
- *
- * @param holder the byte data containing the bits we're
- * interested in
+ * Sets the bits.
*
- * @return the value of holder with the specified bits set
- * to {@code 1}
+ * @param holder the byte data containing the bits we're interested in
+ * @return the value of holder with the specified bits set to {@code 1}
*/
public byte setByte(final byte holder) {
return (byte) set(holder);
}
/**
- *
Sets a boolean BitField.
+ * Sets a boolean BitField.
*
- * @param holder the int data containing the bits we're
- * interested in
- * @param flag indicating whether to set or clear the bits
- * @return the value of holder with the specified bits set or
- * cleared
+ * @param holder the byte data containing the bits we're interested in.
+ * @param flag indicating whether to set or clear the bits.
+ * @return the value of holder with the specified bits set or cleared.
*/
- public int setBoolean(final int holder, final boolean flag) {
- return flag ? set(holder) : clear(holder);
+ public byte setByteBoolean(final byte holder, final boolean flag) {
+ return flag ? setByte(holder) : clearByte(holder);
+ }
+
+ /**
+ * Sets the bits.
+ *
+ * @param holder the short data containing the bits we're interested in.
+ * @return the value of holder with the specified bits set to {@code 1}.
+ */
+ public short setShort(final short holder) {
+ return (short) set(holder);
}
/**
- *
Sets a boolean BitField.
+ * Sets a boolean BitField.
*
- * @param holder the short data containing the bits we're
- * interested in
- * @param flag indicating whether to set or clear the bits
- * @return the value of holder with the specified bits set or
- * cleared
+ * @param holder the short data containing the bits we're interested in.
+ * @param flag indicating whether to set or clear the bits.
+ * @return the value of holder with the specified bits set or cleared.
*/
public short setShortBoolean(final short holder, final boolean flag) {
return flag ? setShort(holder) : clearShort(holder);
}
/**
- *
Sets a boolean BitField.
+ * Sets the bits with new values.
*
- * @param holder the byte data containing the bits we're
- * interested in
- * @param flag indicating whether to set or clear the bits
- * @return the value of holder with the specified bits set or
- * cleared
+ * @param holder the short data containing the bits we're interested in
+ * @param value the new value for the specified bits
+ * @return the value of holder with the bits from the value parameter replacing the old bits
+ * @see #getShortValue(short)
*/
- public byte setByteBoolean(final byte holder, final boolean flag) {
- return flag ? setByte(holder) : clearByte(holder);
+ public short setShortValue(final short holder, final short value) {
+ return (short) setValue(holder, value);
+ }
+
+ /**
+ * Sets the bits with new values.
+ *
+ * @param holder the int data containing the bits we're interested in.
+ * @param value the new value for the specified bits.
+ * @return the value of holder with the bits from the value parameter replacing the old bits.
+ * @see #getValue(int)
+ */
+ public int setValue(final int holder, final int value) {
+ return (int) (holder & ~mask | value << shiftCount & mask);
}
+ /**
+ * Sets the bits with new values.
+ *
+ * @param holder the long data containing the bits we're interested in.
+ * @param value the new value for the specified bits.
+ * @return the value of holder with the bits from the value parameter replacing the old bits.
+ * @see #getValue(long)
+ * @since 3.21.0
+ */
+ public long setValue(final long holder, final long value) {
+ return holder & ~mask | value << shiftCount & mask;
+ }
}
diff --git a/src/main/java/org/apache/commons/lang3/BooleanUtils.java b/src/main/java/org/apache/commons/lang3/BooleanUtils.java
index ba5dea00c8d..7cb0c3e9285 100644
--- a/src/main/java/org/apache/commons/lang3/BooleanUtils.java
+++ b/src/main/java/org/apache/commons/lang3/BooleanUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,97 +16,165 @@
*/
package org.apache.commons.lang3;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
import org.apache.commons.lang3.math.NumberUtils;
/**
- *
Operations on boolean primitives and Boolean objects.
+ * Operations on boolean primitives and Boolean objects.
*
*
This class tries to handle {@code null} input gracefully.
* An exception will not be thrown for a {@code null} input.
- * Each method documents its behaviour in more detail.
+ * Each method documents its behavior in more detail.
*
*
#ThreadSafe#
+ *
* @since 2.0
*/
public class BooleanUtils {
+ private static final List BOOLEAN_LIST = Collections.unmodifiableList(Arrays.asList(Boolean.FALSE, Boolean.TRUE));
+
/**
- *
{@code BooleanUtils} instances should NOT be constructed in standard programming.
- * Instead, the class should be used as {@code BooleanUtils.negate(true);}.
+ * The false String {@code "false"}.
*
- *
This constructor is public to permit tools that require a JavaBean instance
- * to operate.
+ * @since 3.12.0
*/
- public BooleanUtils() {
- super();
- }
+ public static final String FALSE = "false";
- // Boolean utilities
- //--------------------------------------------------------------------------
/**
- *
Negates the specified boolean.
+ * The no String {@code "no"}.
*
- *
If {@code null} is passed in, {@code null} will be returned.
+ * @since 3.12.0
+ */
+ public static final String NO = "no";
+
+ /**
+ * The off String {@code "off"}.
+ *
+ * @since 3.12.0
+ */
+ public static final String OFF = "off";
+
+ /**
+ * The on String {@code "on"}.
+ *
+ * @since 3.12.0
+ */
+ public static final String ON = "on";
+
+ /**
+ * The true String {@code "true"}.
+ *
+ * @since 3.12.0
+ */
+ public static final String TRUE = "true";
+
+ /**
+ * The yes String {@code "yes"}.
*
- *
NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean.
+ * @since 3.12.0
+ */
+ public static final String YES = "yes";
+
+ /**
+ * Performs an 'and' operation on a set of booleans.
*
*
*
- * @param bool the Boolean to negate, may be null
- * @return the negated Boolean, or {@code null} if {@code null} input
+ * @param array an array of {@code boolean}s
+ * @return the result of the logical 'and' operation. That is {@code false}
+ * if any of the parameters is {@code false} and {@code true} otherwise.
+ * @throws NullPointerException if {@code array} is {@code null}
+ * @throws IllegalArgumentException if {@code array} is empty.
+ * @since 3.0.1
*/
- public static Boolean negate(final Boolean bool) {
- if (bool == null) {
- return null;
+ public static boolean and(final boolean... array) {
+ ObjectUtils.requireNonEmpty(array, "array");
+ for (final boolean element : array) {
+ if (!element) {
+ return false;
+ }
}
- return bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
+ return true;
}
- // boolean Boolean methods
- //-----------------------------------------------------------------------
/**
- *
Checks if a {@code Boolean} value is {@code true},
- * handling {@code null} by returning {@code false}.
- *
+ * Performs an 'and' operation on an array of Booleans.
*
+ * Null array elements map to false, like {@code Boolean.parseBoolean(null)} and its callers return false.
+ *
+ *
+ * @param array an array of {@link Boolean}s
+ * @return the result of the logical 'and' operation. That is {@code false}
+ * if any of the parameters is {@code false} and {@code true} otherwise.
+ * @throws NullPointerException if {@code array} is {@code null}
+ * @throws IllegalArgumentException if {@code array} is empty.
+ * @since 3.0.1
+ */
+ public static Boolean and(final Boolean... array) {
+ ObjectUtils.requireNonEmpty(array, "array");
+ return and(ArrayUtils.toPrimitive(array)) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ /**
+ * Returns a new array of possible values (like an enum would).
*
- * @param bool the boolean to check, null returns {@code false}
- * @return {@code true} only if the input is non-null and true
- * @since 2.1
+ * @return a new array of possible values (like an enum would).
+ * @since 3.12.0
*/
- public static boolean isTrue(final Boolean bool) {
- return Boolean.TRUE.equals(bool);
+ public static Boolean[] booleanValues() {
+ return new Boolean[] {Boolean.FALSE, Boolean.TRUE};
}
/**
- *
Checks if a {@code Boolean} value is not {@code true},
- * handling {@code null} by returning {@code true}.
+ * Compares two {@code boolean} values. This is the same functionality as provided in Java 7.
*
- *
+ * @param x the first {@code boolean} to compare
+ * @param y the second {@code boolean} to compare
+ * @return the value {@code 0} if {@code x == y};
+ * a value less than {@code 0} if {@code !x && y}; and
+ * a value greater than {@code 0} if {@code x && !y}
+ * @since 3.4
+ */
+ public static int compare(final boolean x, final boolean y) {
+ if (x == y) {
+ return 0;
+ }
+ return x ? 1 : -1;
+ }
+
+ /**
+ * Performs the given action for each Boolean {@link BooleanUtils#values()}.
*
- * @param bool the boolean to check, null returns {@code true}
- * @return {@code true} if the input is null or false
- * @since 2.3
+ * @param action The action to be performed for each element
+ * @since 3.13.0
*/
- public static boolean isNotTrue(final Boolean bool) {
- return !isTrue(bool);
+ public static void forEach(final Consumer action) {
+ values().forEach(action);
}
/**
- *
Checks if a {@code Boolean} value is {@code false},
- * handling {@code null} by returning {@code false}.
+ * Checks if a {@link Boolean} value is {@code false},
+ * handling {@code null} by returning {@code false}.
*
*
*
* @param bool the boolean to check, null returns {@code false}
- * @return {@code true} only if the input is non-null and false
+ * @return {@code true} only if the input is non-{@code null} and {@code false}
* @since 2.1
*/
public static boolean isFalse(final Boolean bool) {
@@ -123,8 +191,8 @@ public static boolean isFalse(final Boolean bool) {
}
/**
- *
Checks if a {@code Boolean} value is not {@code false},
- * handling {@code null} by returning {@code true}.
+ * Checks if a {@link Boolean} value is not {@code false},
+ * handling {@code null} by returning {@code true}.
*
*
*
- * @param value the int to convert
- * @return {@code true} if non-zero, {@code false}
- * if zero
+ * @param array an array of {@code boolean}s
+ * @return {@code true} if any of the arguments is {@code true}, and it returns {@code false} otherwise.
+ * @throws NullPointerException if {@code array} is {@code null}
+ * @throws IllegalArgumentException if {@code array} is empty.
+ * @since 3.0.1
*/
- public static boolean toBoolean(final int value) {
- return value != 0;
+ public static boolean or(final boolean... array) {
+ ObjectUtils.requireNonEmpty(array, "array");
+ for (final boolean element : array) {
+ if (element) {
+ return true;
+ }
+ }
+ return false;
}
/**
- *
Converts an int to a Boolean using the convention that {@code zero}
- * is {@code false}.
- *
+ * Performs an 'or' operation on an array of Booleans.
*
+ * Null array elements map to false, like {@code Boolean.parseBoolean(null)} and its callers return false.
+ *
*
- * @param value the int to convert
- * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
- * {@code null} if {@code null}
+ * @param array an array of {@link Boolean}s
+ * @return {@code true} if any of the arguments is {@code true}, and it returns {@code false} otherwise.
+ * @throws NullPointerException if {@code array} is {@code null}
+ * @throws IllegalArgumentException if {@code array} is empty.
+ * @since 3.0.1
*/
- public static Boolean toBooleanObject(final int value) {
- return value == 0 ? Boolean.FALSE : Boolean.TRUE;
+ public static Boolean or(final Boolean... array) {
+ ObjectUtils.requireNonEmpty(array, "array");
+ return or(ArrayUtils.toPrimitive(array)) ? Boolean.TRUE : Boolean.FALSE;
}
/**
- *
Converts an Integer to a Boolean using the convention that {@code zero}
- * is {@code false}.
+ * Returns a new array of possible values (like an enum would).
*
- *
{@code null} will be converted to {@code null}.
+ * @return a new array of possible values (like an enum would).
+ * @since 3.12.0
+ */
+ public static boolean[] primitiveValues() {
+ return new boolean[] {false, true};
+ }
+
+ /**
+ * Converts a Boolean to a boolean handling {@code null}
+ * by returning {@code false}.
*
- *
NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean.
*
- * @param value the Integer to convert
+ * @param value the {@link Integer} to convert
* @param trueValue the value to match for {@code true}
* @param falseValue the value to match for {@code false}
* @return {@code true} or {@code false}
- * @throws IllegalArgumentException if no match
+ * @throws IllegalArgumentException if {@code value} does not match neither
+ * {@code trueValue} no {@code falseValue}
*/
public static boolean toBoolean(final int value, final int trueValue, final int falseValue) {
if (value == trueValue) {
@@ -264,12 +446,11 @@ public static boolean toBoolean(final int value, final int trueValue, final int
if (value == falseValue) {
return false;
}
- // no match
throw new IllegalArgumentException("The Integer did not match either specified value");
}
/**
- *
Converts an Integer to a boolean specifying the conversion values.
+ * Converts an Integer to a boolean specifying the conversion values.
*
*
* BooleanUtils.toBoolean(Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(0)) = false
@@ -298,230 +479,239 @@ public static boolean toBoolean(final Integer value, final Integer trueValue, fi
} else if (value.equals(falseValue)) {
return false;
}
- // no match
throw new IllegalArgumentException("The Integer did not match either specified value");
}
/**
- *
Converts an int to a Boolean specifying the conversion values.
+ * Converts a String to a boolean (optimized for performance).
*
- *
NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean.
+ *
{@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'}
+ * (case insensitive) will return {@code true}. Otherwise,
+ * {@code false} is returned.
This method performs 4 times faster (JDK1.4) than
+ * {@code Boolean.valueOf(String)}. However, this method accepts
+ * 'on' and 'yes', 't', 'y' as true values.
*
- * @param value the Integer to convert
- * @param trueValue the value to match for {@code true}
- * @param falseValue the value to match for {@code false}
- * @param nullValue the value to to match for {@code null}
- * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
- * @throws IllegalArgumentException if no match
+ *
+ *
+ * @param str the String to check
+ * @return the boolean value of the string, {@code false} if no match or the String is null
*/
- public static Boolean toBooleanObject(final int value, final int trueValue, final int falseValue, final int nullValue) {
- if (value == trueValue) {
- return Boolean.TRUE;
- }
- if (value == falseValue) {
- return Boolean.FALSE;
- }
- if (value == nullValue) {
- return null;
- }
- // no match
- throw new IllegalArgumentException("The Integer did not match any specified value");
+ public static boolean toBoolean(final String str) {
+ return toBooleanObject(str) == Boolean.TRUE;
}
/**
- *
Converts an Integer to a Boolean specifying the conversion values.
- *
- *
NOTE: This returns null and will throw a NullPointerException if autoboxed to a boolean.
+ * Converts a String to a Boolean throwing an exception if no match found.
*
*
*
- * @param value the Integer to convert
- * @param trueValue the value to match for {@code true}, may be {@code null}
- * @param falseValue the value to match for {@code false}, may be {@code null}
- * @param nullValue the value to to match for {@code null}, may be {@code null}
- * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
- * @throws IllegalArgumentException if no match
+ * @param str the String to check
+ * @param trueString the String to match for {@code true} (case-sensitive), may be {@code null}
+ * @param falseString the String to match for {@code false} (case-sensitive), may be {@code null}
+ * @return the boolean value of the string
+ * @throws IllegalArgumentException if the String doesn't match
*/
- public static Boolean toBooleanObject(final Integer value, final Integer trueValue, final Integer falseValue, final Integer nullValue) {
- if (value == null) {
- if (trueValue == null) {
- return Boolean.TRUE;
- }
- if (falseValue == null) {
- return Boolean.FALSE;
+ public static boolean toBoolean(final String str, final String trueString, final String falseString) {
+ if (str == trueString) {
+ return true;
+ }
+ if (str == falseString) {
+ return false;
+ }
+ if (str != null) {
+ if (str.equals(trueString)) {
+ return true;
}
- if (nullValue == null) {
- return null;
+ if (str.equals(falseString)) {
+ return false;
}
- } else if (value.equals(trueValue)) {
- return Boolean.TRUE;
- } else if (value.equals(falseValue)) {
- return Boolean.FALSE;
- } else if (value.equals(nullValue)) {
- return null;
}
- // no match
- throw new IllegalArgumentException("The Integer did not match any specified value");
+ throw new IllegalArgumentException("The String did not match either specified value");
}
- // Boolean to Integer methods
- //-----------------------------------------------------------------------
/**
- *
Converts a boolean to an int using the convention that
- * {@code zero} is {@code false}.
+ * Converts a Boolean to a boolean handling {@code null}.
*
*
*
- * @param bool the boolean to convert
- * @return one if {@code true}, zero if {@code false}
+ * @param bool the boolean object to convert to primitive
+ * @param valueIfNull the boolean value to return if the parameter {@code bool} is {@code null}
+ * @return {@code true} or {@code false}
*/
- public static int toInteger(final boolean bool) {
- return bool ? 1 : 0;
+ public static boolean toBooleanDefaultIfNull(final Boolean bool, final boolean valueIfNull) {
+ if (bool == null) {
+ return valueIfNull;
+ }
+ return bool.booleanValue();
}
/**
- *
Converts a boolean to an Integer using the convention that
- * {@code zero} is {@code false}.
+ * Converts an int to a Boolean using the convention that {@code zero}
+ * is {@code false}, everything else is {@code true}.
*
*
*
- * @param bool the boolean to convert
- * @return one if {@code true}, zero if {@code false}
+ * @param value the int to convert
+ * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
+ * {@code null} if {@code null}
*/
- public static Integer toIntegerObject(final boolean bool) {
- return bool ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
+ public static Boolean toBooleanObject(final int value) {
+ return value == 0 ? Boolean.FALSE : Boolean.TRUE;
}
/**
- *
Converts a Boolean to a Integer using the convention that
- * {@code zero} is {@code false}.
+ * Converts an int to a Boolean specifying the conversion values.
*
- *
{@code null} will be converted to {@code null}.
+ *
NOTE: This method may return {@code null} and may throw a {@link NullPointerException}
+ * if unboxed to a {@code boolean}.
+ *
+ *
The checks are done first for the {@code trueValue}, then for the {@code falseValue} and
+ * finally for the {@code nullValue}.
*
- * @param bool the Boolean to convert
- * @return one if Boolean.TRUE, zero if Boolean.FALSE, {@code null} if {@code null}
+ * @param value the Integer to convert
+ * @param trueValue the value to match for {@code true}
+ * @param falseValue the value to match for {@code false}
+ * @param nullValue the value to match for {@code null}
+ * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
+ * @throws IllegalArgumentException if no match
*/
- public static Integer toIntegerObject(final Boolean bool) {
- if (bool == null) {
+ public static Boolean toBooleanObject(final int value, final int trueValue, final int falseValue, final int nullValue) {
+ if (value == trueValue) {
+ return Boolean.TRUE;
+ }
+ if (value == falseValue) {
+ return Boolean.FALSE;
+ }
+ if (value == nullValue) {
return null;
}
- return bool.booleanValue() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO;
+ throw new IllegalArgumentException("The Integer did not match any specified value");
}
/**
- *
Converts a boolean to an int specifying the conversion values.
+ * Converts an Integer to a Boolean using the convention that {@code zero}
+ * is {@code false}, every other numeric value is {@code true}.
*
- *
*
- * @param bool the to convert
- * @param trueValue the value to return if {@code true}
- * @param falseValue the value to return if {@code false}
- * @return the appropriate value
- */
- public static int toInteger(final boolean bool, final int trueValue, final int falseValue) {
- return bool ? trueValue : falseValue;
- }
-
- /**
- *
Converts a Boolean to an int specifying the conversion values.
+ *
NOTE: This method may return {@code null} and may throw a {@link NullPointerException}
+ * if unboxed to a {@code boolean}.
*
- * @param bool the Boolean to convert
- * @param trueValue the value to return if {@code true}
- * @param falseValue the value to return if {@code false}
- * @param nullValue the value to return if {@code null}
- * @return the appropriate value
+ * @param value the Integer to convert
+ * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero,
+ * {@code null} if {@code null} input
*/
- public static int toInteger(final Boolean bool, final int trueValue, final int falseValue, final int nullValue) {
- if (bool == null) {
- return nullValue;
+ public static Boolean toBooleanObject(final Integer value) {
+ if (value == null) {
+ return null;
}
- return bool.booleanValue() ? trueValue : falseValue;
+ return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
}
/**
- *
Converts a boolean to an Integer specifying the conversion values.
+ * Converts an Integer to a Boolean specifying the conversion values.
*
- *
- *
- * @param bool the to convert
- * @param trueValue the value to return if {@code true}, may be {@code null}
- * @param falseValue the value to return if {@code false}, may be {@code null}
- * @return the appropriate value
- */
- public static Integer toIntegerObject(final boolean bool, final Integer trueValue, final Integer falseValue) {
- return bool ? trueValue : falseValue;
- }
-
- /**
- *
Converts a Boolean to an Integer specifying the conversion values.
+ *
NOTE: This method may return {@code null} and may throw a {@link NullPointerException}
+ * if unboxed to a {@code boolean}.
*
+ *
The checks are done first for the {@code trueValue}, then for the {@code falseValue} and
+ * finally for the {@code nullValue}.
*
- * @param bool the Boolean to convert
- * @param trueValue the value to return if {@code true}, may be {@code null}
- * @param falseValue the value to return if {@code false}, may be {@code null}
- * @param nullValue the value to return if {@code null}, may be {@code null}
- * @return the appropriate value
+ * @param value the Integer to convert
+ * @param trueValue the value to match for {@code true}, may be {@code null}
+ * @param falseValue the value to match for {@code false}, may be {@code null}
+ * @param nullValue the value to match for {@code null}, may be {@code null}
+ * @return Boolean.TRUE, Boolean.FALSE, or {@code null}
+ * @throws IllegalArgumentException if no match
*/
- public static Integer toIntegerObject(final Boolean bool, final Integer trueValue, final Integer falseValue, final Integer nullValue) {
- if (bool == null) {
- return nullValue;
+ public static Boolean toBooleanObject(final Integer value, final Integer trueValue, final Integer falseValue, final Integer nullValue) {
+ if (value == null) {
+ if (trueValue == null) {
+ return Boolean.TRUE;
+ }
+ if (falseValue == null) {
+ return Boolean.FALSE;
+ }
+ if (nullValue == null) {
+ return null;
+ }
+ } else if (value.equals(trueValue)) {
+ return Boolean.TRUE;
+ } else if (value.equals(falseValue)) {
+ return Boolean.FALSE;
+ } else if (value.equals(nullValue)) {
+ return null;
}
- return bool.booleanValue() ? trueValue : falseValue;
+ throw new IllegalArgumentException("The Integer did not match any specified value");
}
- // String to Boolean methods
- //-----------------------------------------------------------------------
/**
- *
*
* @param str the String to check
- * @param trueString the String to match for {@code true} (case sensitive), may be {@code null}
- * @param falseString the String to match for {@code false} (case sensitive), may be {@code null}
- * @param nullString the String to match for {@code null} (case sensitive), may be {@code null}
+ * @param trueString the String to match for {@code true} (case-sensitive), may be {@code null}
+ * @param falseString the String to match for {@code false} (case-sensitive), may be {@code null}
+ * @param nullString the String to match for {@code null} (case-sensitive), may be {@code null}
* @return the Boolean value of the string, {@code null} if either the String matches {@code nullString}
* or if {@code null} input and {@code nullString} is {@code null}
* @throws IllegalArgumentException if the String doesn't match
@@ -674,126 +875,156 @@ public static Boolean toBooleanObject(final String str, final String trueString,
throw new IllegalArgumentException("The String did not match any specified value");
}
- // String to boolean methods
- //-----------------------------------------------------------------------
/**
- *
Converts a String to a boolean (optimised for performance).
+ * Converts a boolean to an int using the convention that
+ * {@code true} is {@code 1} and {@code false} is {@code 0}.
*
- *
{@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'}
- * (case insensitive) will return {@code true}. Otherwise,
- * {@code false} is returned.
This method performs 4 times faster (JDK1.4) than
- * {@code Boolean.valueOf(String)}. However, this method accepts
- * 'on' and 'yes', 't', 'y' as true values.
+ * @param bool the boolean to convert
+ * @return one if {@code true}, zero if {@code false}
+ */
+ public static int toInteger(final boolean bool) {
+ return bool ? 1 : 0;
+ }
+
+ /**
+ * Converts a boolean to an int specifying the conversion values.
*
*
*
- * @param str the String to check
- * @return the boolean value of the string, {@code false} if no match or the String is null
+ * @param bool the to convert
+ * @param trueValue the value to return if {@code true}
+ * @param falseValue the value to return if {@code false}
+ * @return the appropriate value
*/
- public static boolean toBoolean(final String str) {
- return toBooleanObject(str) == Boolean.TRUE;
+ public static int toInteger(final boolean bool, final int trueValue, final int falseValue) {
+ return bool ? trueValue : falseValue;
}
/**
- *
Converts a String to a Boolean throwing an exception if no match found.
+ * Converts a Boolean to an int specifying the conversion values.
*
*
*
- * @param str the String to check
- * @param trueString the String to match for {@code true} (case sensitive), may be {@code null}
- * @param falseString the String to match for {@code false} (case sensitive), may be {@code null}
- * @return the boolean value of the string
- * @throws IllegalArgumentException if the String doesn't match
+ * @param bool the Boolean to convert
+ * @param trueValue the value to return if {@code true}
+ * @param falseValue the value to return if {@code false}
+ * @param nullValue the value to return if {@code null}
+ * @return the appropriate value
*/
- public static boolean toBoolean(final String str, final String trueString, final String falseString) {
- if (str == trueString) {
- return true;
- } else if (str == falseString) {
- return false;
- } else if (str != null) {
- if (str.equals(trueString)) {
- return true;
- } else if (str.equals(falseString)) {
- return false;
- }
+ public static int toInteger(final Boolean bool, final int trueValue, final int falseValue, final int nullValue) {
+ if (bool == null) {
+ return nullValue;
}
- // no match
- throw new IllegalArgumentException("The String did not match either specified value");
+ return bool.booleanValue() ? trueValue : falseValue;
}
- // Boolean to String methods
- //-----------------------------------------------------------------------
/**
- *
Converts a Boolean to a String returning {@code 'true'},
- * {@code 'false'}, or {@code null}.
+ * Converts a boolean to an Integer using the convention that
+ * {@code true} is {@code 1} and {@code false} is {@code 0}.
*
*
*
- * @param bool the Boolean to check
- * @return {@code 'on'}, {@code 'off'}, or {@code null}
+ * @param bool the to convert
+ * @param trueValue the value to return if {@code true}, may be {@code null}
+ * @param falseValue the value to return if {@code false}, may be {@code null}
+ * @return the appropriate value
*/
- public static String toStringOnOff(final Boolean bool) {
- return toString(bool, "on", "off", null);
+ public static Integer toIntegerObject(final boolean bool, final Integer trueValue, final Integer falseValue) {
+ return bool ? trueValue : falseValue;
}
/**
- *
Converts a Boolean to a String returning {@code 'yes'},
- * {@code 'no'}, or {@code null}.
+ * Converts a Boolean to an Integer using the convention that
+ * {@code zero} is {@code false}.
+ *
+ *
+ *
+ * @param bool the Boolean to convert
+ * @param trueValue the value to return if {@code true}, may be {@code null}
+ * @param falseValue the value to return if {@code false}, may be {@code null}
+ * @param nullValue the value to return if {@code null}, may be {@code null}
+ * @return the appropriate value
+ */
+ public static Integer toIntegerObject(final Boolean bool, final Integer trueValue, final Integer falseValue, final Integer nullValue) {
+ if (bool == null) {
+ return nullValue;
+ }
+ return bool.booleanValue() ? trueValue : falseValue;
+ }
+
+ /**
+ * Converts a boolean to a String returning one of the input Strings.
+ *
+ *
*
* @param bool the Boolean to check
- * @return {@code 'yes'}, {@code 'no'}, or {@code null}
+ * @param trueString the String to return if {@code true}, may be {@code null}
+ * @param falseString the String to return if {@code false}, may be {@code null}
+ * @return one of the two input Strings
*/
- public static String toStringYesNo(final Boolean bool) {
- return toString(bool, "yes", "no", null);
+ public static String toString(final boolean bool, final String trueString, final String falseString) {
+ return bool ? trueString : falseString;
}
/**
- *
Converts a Boolean to a String returning one of the input Strings.
+ * Converts a Boolean to a String returning one of the input Strings.
*
*
* BooleanUtils.toString(Boolean.TRUE, "true", "false", null) = "true"
@@ -814,27 +1045,9 @@ public static String toString(final Boolean bool, final String trueString, final
return bool.booleanValue() ? trueString : falseString;
}
- // boolean to String methods
- //-----------------------------------------------------------------------
- /**
- *
Converts a boolean to a String returning {@code 'true'}
- * or {@code 'false'}.
*
* @param bool the Boolean to check
- * @param trueString the String to return if {@code true}, may be {@code null}
- * @param falseString the String to return if {@code false}, may be {@code null}
- * @return one of the two input Strings
+ * @return {@code 'true'}, {@code 'false'}, or {@code null}
*/
- public static String toString(final boolean bool, final String trueString, final String falseString) {
- return bool ? trueString : falseString;
+ public static String toStringTrueFalse(final boolean bool) {
+ return toString(bool, TRUE, FALSE);
}
- // logical operations
- // ----------------------------------------------------------------------
/**
- *
Performs an and on a set of booleans.
+ * Converts a Boolean to a String returning {@code 'true'},
+ * {@code 'false'}, or {@code null}.
*
*
- *
- * @param array an array of {@code Boolean}s
- * @return {@code true} if the or is successful.
- * @throws IllegalArgumentException if {@code array} is {@code null}
- * @throws IllegalArgumentException if {@code array} is empty.
- * @throws IllegalArgumentException if {@code array} contains a {@code null}
- * @since 3.0.1
+ * @return an unmodifiable list of Booleans {@code [false, true]}.
+ * @since 3.13.0
*/
- public static Boolean or(final Boolean... array) {
- if (array == null) {
- throw new IllegalArgumentException("The Array must not be null");
- }
- if (array.length == 0) {
- throw new IllegalArgumentException("Array is empty");
- }
- try {
- final boolean[] primitive = ArrayUtils.toPrimitive(array);
- return or(primitive) ? Boolean.TRUE : Boolean.FALSE;
- } catch (final NullPointerException ex) {
- throw new IllegalArgumentException("The array must not contain any null elements");
- }
+ public static List values() {
+ return BOOLEAN_LIST;
}
/**
- *
Performs an xor on a set of booleans.
+ * Performs an xor on a set of booleans.
+ *
+ * This behaves like an XOR gate;
+ * it returns true if the number of true values is odd,
+ * and false if the number of true values is zero or even.
+ *
*
* @param array an array of {@code boolean}s
- * @return {@code true} if the xor is successful.
- * @throws IllegalArgumentException if {@code array} is {@code null}
+ * @return true if the number of true values in the array is odd; otherwise returns false.
+ * @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty.
*/
public static boolean xor(final boolean... array) {
- // Validates input
- if (array == null) {
- throw new IllegalArgumentException("The Array must not be null");
- }
- if (array.length == 0) {
- throw new IllegalArgumentException("Array is empty");
- }
-
+ ObjectUtils.requireNonEmpty(array, "array");
// false if the neutral element of the xor operator
boolean result = false;
for (final boolean element : array) {
@@ -1055,54 +1188,41 @@ public static boolean xor(final boolean... array) {
}
/**
- *
Performs an xor on an array of Booleans.
- *
+ * Performs an xor on an array of Booleans.
*
+ * Null array elements map to false, like {@code Boolean.parseBoolean(null)} and its callers return false.
+ *
*
- * @param array an array of {@code Boolean}s
- * @return {@code true} if the xor is successful.
- * @throws IllegalArgumentException if {@code array} is {@code null}
+ * @param array an array of {@link Boolean}s
+ * @return the result of the xor operations
+ * @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty.
- * @throws IllegalArgumentException if {@code array} contains a {@code null}
*/
public static Boolean xor(final Boolean... array) {
- if (array == null) {
- throw new IllegalArgumentException("The Array must not be null");
- }
- if (array.length == 0) {
- throw new IllegalArgumentException("Array is empty");
- }
- try {
- final boolean[] primitive = ArrayUtils.toPrimitive(array);
- return xor(primitive) ? Boolean.TRUE : Boolean.FALSE;
- } catch (final NullPointerException ex) {
- throw new IllegalArgumentException("The array must not contain any null elements");
- }
+ ObjectUtils.requireNonEmpty(array, "array");
+ return xor(ArrayUtils.toPrimitive(array)) ? Boolean.TRUE : Boolean.FALSE;
}
/**
- *
Compares two {@code boolean} values. This is the same functionality as provided in Java 7.
+ * {@link BooleanUtils} instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as {@code BooleanUtils.negate(true);}.
*
- * @param x the first {@code boolean} to compare
- * @param y the second {@code boolean} to compare
- * @return the value {@code 0} if {@code x == y};
- * a value less than {@code 0} if {@code !x && y}; and
- * a value greater than {@code 0} if {@code x && !y}
- * @since 3.4
+ *
This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
+ *
+ * @deprecated TODO Make private in 4.0.
*/
- public static int compare(boolean x, boolean y) {
- if (x == y) {
- return 0;
- }
- if (x) {
- return 1;
- } else {
- return -1;
- }
+ @Deprecated
+ public BooleanUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/CachedRandomBits.java b/src/main/java/org/apache/commons/lang3/CachedRandomBits.java
new file mode 100644
index 00000000000..62904c34627
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/CachedRandomBits.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3;
+
+import java.util.Objects;
+import java.util.Random;
+
+/**
+ * Generates random integers of specific bit length.
+ *
+ *
+ * It is more efficient than calling Random.nextInt(1 << nbBits). It uses a cache of cacheSize random bytes that it replenishes when it gets empty. This is
+ * especially beneficial for SecureRandom Drbg implementations, which incur a constant cost at each randomness generation.
+ *
+ *
+ *
+ * Used internally by RandomStringUtils.
+ *
+ *
+ *
+ * #NotThreadSafe#
+ *
+ */
+final class CachedRandomBits {
+
+ /**
+ * The maximum size of the cache.
+ *
+ *
+ * This is to prevent the possibility of overflow in the {@code if (bitIndex >> 3 >= cache.length)} in the {@link #nextBits(int)} method.
+ *
+ */
+ private static final int MAX_CACHE_SIZE = Integer.MAX_VALUE >> 3;
+
+ /** Maximum number of bits that can be generated (size of an int) */
+ private static final int MAX_BITS = 32;
+
+ /** Mask to extract the bit offset within a byte (0-7) */
+ private static final int BIT_INDEX_MASK = 0x7;
+
+ /** Number of bits in a byte */
+ private static final int BITS_PER_BYTE = 8;
+ private final Random random;
+ private final byte[] cache;
+
+ /**
+ * Index of the next bit in the cache to be used.
+ *
+ *
+ *
bitIndex=0 means the cache is fully random and none of the bits have been used yet.
+ *
bitIndex=1 means that only the LSB of cache[0] has been used and all other bits can be used.
+ *
bitIndex=8 means that only the 8 bits of cache[0] has been used.
+ *
+ */
+ private int bitIndex;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param cacheSize number of bytes cached (only affects performance)
+ * @param random random source
+ */
+ CachedRandomBits(final int cacheSize, final Random random) {
+ if (cacheSize <= 0) {
+ throw new IllegalArgumentException("cacheSize must be positive");
+ }
+ this.cache = cacheSize <= MAX_CACHE_SIZE ? new byte[cacheSize] : new byte[MAX_CACHE_SIZE];
+ this.random = Objects.requireNonNull(random, "random");
+ this.random.nextBytes(this.cache);
+ this.bitIndex = 0;
+ }
+
+ /**
+ * Generates a random integer with the specified number of bits.
+ *
+ *
This method efficiently generates random bits by using a byte cache and bit manipulation:
+ *
+ *
Uses a byte array cache to avoid frequent calls to the underlying random number generator
+ *
Extracts bits from each byte using bit shifting and masking
+ *
Handles partial bytes to avoid wasting random bits
+ *
Accumulates bits until the requested number is reached
+ *
+ *
+ *
+ * @param bits number of bits to generate, MUST be between 1 and 32 (inclusive)
+ * @return random integer containing exactly the requested number of random bits
+ * @throws IllegalArgumentException if bits is not between 1 and 32
+ */
+ public int nextBits(final int bits) {
+ if (bits > MAX_BITS || bits <= 0) {
+ throw new IllegalArgumentException("number of bits must be between 1 and " + MAX_BITS);
+ }
+ int result = 0;
+ int generatedBits = 0; // number of generated bits up to now
+ while (generatedBits < bits) {
+ // Check if we need to refill the cache
+ // Convert bitIndex to byte index by dividing by 8 (right shift by 3)
+ if (bitIndex >> 3 >= cache.length) {
+ // We exhausted the number of bits in the cache
+ // This should only happen if the bitIndex is exactly matching the cache length
+ assert bitIndex == cache.length * BITS_PER_BYTE;
+ random.nextBytes(cache);
+ bitIndex = 0;
+ }
+ // Calculate how many bits we can extract from the current byte
+ // 1. Get current position within byte (0-7) using bitIndex & 0x7
+ // 2. Calculate remaining bits in byte: 8 - (position within byte)
+ // 3. Take minimum of remaining bits in byte and bits still needed
+ final int generatedBitsInIteration = Math.min(
+ BITS_PER_BYTE - (bitIndex & BIT_INDEX_MASK),
+ bits - generatedBits);
+ // Shift existing result left to make room for new bits
+ result = result << generatedBitsInIteration;
+ // Extract and append new bits:
+ // 1. Get byte from cache (bitIndex >> 3 converts bit index to byte index)
+ // 2. Shift right by bit position within byte (bitIndex & 0x7)
+ // 3. Mask to keep only the bits we want ((1 << generatedBitsInIteration) - 1)
+ result |= cache[bitIndex >> 3] >> (bitIndex & BIT_INDEX_MASK) & ((1 << generatedBitsInIteration) - 1);
+ // Update counters
+ generatedBits += generatedBitsInIteration;
+ bitIndex += generatedBitsInIteration;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/apache/commons/lang3/CharEncoding.java b/src/main/java/org/apache/commons/lang3/CharEncoding.java
index ea682847c90..072e94fec90 100644
--- a/src/main/java/org/apache/commons/lang3/CharEncoding.java
+++ b/src/main/java/org/apache/commons/lang3/CharEncoding.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,77 +19,84 @@
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
/**
- *
Character encoding names required of every implementation of the Java platform.
+ * Character encoding names required of every implementation of the Java platform.
*
- *
Every implementation of the Java platform is required to support the following character encodings.
* Consult the release documentation for your implementation to see if any other encodings are supported.
*
*
- * @see JRE character encoding names
+ * @see JRE character encoding names
* @since 2.1
+ * @deprecated Java 7 introduced {@link java.nio.charset.StandardCharsets}, which defines these constants as
+ * {@link Charset} objects. Use {@link Charset#name()} to get the string values provided in this class.
+ * This class will be removed in a future release.
*/
+@Deprecated
public class CharEncoding {
/**
- *
ISO Latin Alphabet #1, also known as ISO-LATIN-1.
+ * ISO Latin Alphabet #1, also known as ISO-LATIN-1.
*
*
Every implementation of the Java platform is required to support this character encoding.
*/
- public static final String ISO_8859_1 = "ISO-8859-1";
+ public static final String ISO_8859_1 = StandardCharsets.ISO_8859_1.name();
/**
- *
Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block
- * of the Unicode character set.
+ * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block
+ * of the Unicode character set.
*
*
Every implementation of the Java platform is required to support this character encoding.
*/
- public static final String US_ASCII = "US-ASCII";
+ public static final String US_ASCII = StandardCharsets.US_ASCII.name();
/**
- *
Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial
- * byte-order mark (either order accepted on input, big-endian used on output).
+ * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial
+ * byte-order mark (either order accepted on input, big-endian used on output).
*
*
Every implementation of the Java platform is required to support this character encoding.
*/
- public static final String UTF_16 = "UTF-16";
+ public static final String UTF_16 = StandardCharsets.UTF_16.name();
/**
- *
Sixteen-bit Unicode Transformation Format, big-endian byte order.
*
* @param name the name of the requested charset; may be either a canonical name or an alias, null returns false
* @return {@code true} if the charset is available in the current Java virtual machine
+ * @deprecated Please use {@link Charset#isSupported(String)} instead, although be aware that {@code null}
+ * values are not accepted by that method and an {@link IllegalCharsetNameException} may be thrown.
*/
+ @Deprecated
public static boolean isSupported(final String name) {
if (name == null) {
return false;
@@ -101,4 +108,13 @@ public static boolean isSupported(final String name) {
}
}
+ /**
+ * Constructs a new instance.
+ *
+ * @deprecated Will be removed in 4.0.0.
+ */
+ @Deprecated
+ public CharEncoding() {
+ // empty
+ }
}
diff --git a/src/main/java/org/apache/commons/lang3/CharRange.java b/src/main/java/org/apache/commons/lang3/CharRange.java
index 2ccda7c4eac..e38efeb3246 100644
--- a/src/main/java/org/apache/commons/lang3/CharRange.java
+++ b/src/main/java/org/apache/commons/lang3/CharRange.java
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,69 +19,135 @@
import java.io.Serializable;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
/**
- *
A contiguous range of characters, optionally negated.
- *
+ * A contiguous range of characters, optionally negated.
+ *
*
Instances are immutable.
*
*
#ThreadSafe#
+ *
* @since 1.0
+ * @since 3.21.0 {@code serialVersionUID} changed from {@code 8270183163158333422L} to {@code 2L}.
*/
-// TODO: This is no longer public and will be removed later as CharSet is moved
+// TODO: This is no longer public and will be removed later as CharSet is moved
// to depend on Range.
final class CharRange implements Iterable, Serializable {
/**
- * Required for serialization support. Lang version 2.0.
- *
- * @see java.io.Serializable
+ * Character {@link Iterator}.
+ *
#NotThreadSafe#
*/
- private static final long serialVersionUID = 8270183163158333422L;
-
- /** The first character, inclusive, in the range. */
- private final char start;
- /** The last character, inclusive, in the range. */
- private final char end;
- /** True if the range is everything except the characters specified. */
- private final boolean negated;
-
- /** Cached toString. */
- private transient String iToString;
+ private static final class CharacterIterator implements Iterator {
+
+ /** The current character */
+ private char current;
+
+ private final CharRange range;
+ private boolean hasNext;
+
+ /**
+ * Constructs a new iterator for the character range.
+ *
+ * @param r The character range.
+ */
+ private CharacterIterator(final CharRange r) {
+ range = r;
+ hasNext = true;
+
+ if (range.negated) {
+ if (range.start == 0) {
+ if (range.end == Character.MAX_VALUE) {
+ // This range is an empty set
+ hasNext = false;
+ } else {
+ current = (char) (range.end + 1);
+ }
+ } else {
+ current = 0;
+ }
+ } else {
+ current = range.start;
+ }
+ }
+
+ /**
+ * Tests whether this iterator reached the end character.
+ *
+ * @return {@code true} if the iterator has yet to reach the character date.
+ */
+ @Override
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ /**
+ * Returns the next character in the iteration.
+ *
+ * @return {@link Character} for the next character.
+ */
+ @Override
+ public Character next() {
+ if (!hasNext) {
+ throw new NoSuchElementException();
+ }
+ final char cur = current;
+ prepareNext();
+ return Character.valueOf(cur);
+ }
+
+ /**
+ * Prepares the next character in the range.
+ */
+ private void prepareNext() {
+ if (range.negated) {
+ if (current == Character.MAX_VALUE) {
+ hasNext = false;
+ } else if (current + 1 == range.start) {
+ if (range.end == Character.MAX_VALUE) {
+ hasNext = false;
+ } else {
+ current = (char) (range.end + 1);
+ }
+ } else {
+ current = (char) (current + 1);
+ }
+ } else if (current < range.end) {
+ current = (char) (current + 1);
+ } else {
+ hasNext = false;
+ }
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @throws UnsupportedOperationException Always thrown.
+ * @see java.util.Iterator#remove()
+ */
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
/**
- *
Constructs a {@code CharRange} over a set of characters,
- * optionally negating the range.
- *
- *
A negated range includes everything except that defined by the
- * start and end characters.
- *
- *
If start and end are in the wrong order, they are reversed.
- * Thus {@code a-e} is the same as {@code e-a}.
+ * Required for serialization support. Lang version 2.0.
*
- * @param start first character, inclusive, in this range
- * @param end last character, inclusive, in this range
- * @param negated true to express everything except the range
+ * @see java.io.Serializable
+ * @since 3.21.0 {@code serialVersionUID} changed from {@code 8270183163158333422L} to {@value}.
*/
- private CharRange(char start, char end, final boolean negated) {
- super();
- if (start > end) {
- final char temp = start;
- start = end;
- end = temp;
- }
-
- this.start = start;
- this.end = end;
- this.negated = negated;
- }
+ private static final long serialVersionUID = 2L;
+
+ /** Empty array. */
+ static final CharRange[] EMPTY_ARRAY = {};
/**
- *
Constructs a {@code CharRange} over a single character.
+ * Constructs a {@link CharRange} over a single character.
*
- * @param ch only character in this range
- * @return the new CharRange object
- * @see CharRange#CharRange(char, char, boolean)
+ * @param ch only character in this range.
+ * @return the new CharRange object.
* @since 2.5
*/
public static CharRange is(final char ch) {
@@ -89,99 +155,110 @@ public static CharRange is(final char ch) {
}
/**
- *
Constructs a negated {@code CharRange} over a single character.
+ * Constructs a {@link CharRange} over a set of characters.
*
- * @param ch only character in this range
- * @return the new CharRange object
- * @see CharRange#CharRange(char, char, boolean)
+ *
If start and end are in the wrong order, they are reversed.
+ * Thus {@code a-e} is the same as {@code e-a}.
+ *
+ * @param start first character, inclusive, in this range.
+ * @param end last character, inclusive, in this range.
+ * @return the new CharRange object.
* @since 2.5
*/
- public static CharRange isNot(final char ch) {
- return new CharRange(ch, ch, true);
+ public static CharRange isIn(final char start, final char end) {
+ return new CharRange(start, end, false);
}
/**
- *
Constructs a {@code CharRange} over a set of characters.
+ * Constructs a negated {@link CharRange} over a single character.
*
- * @param start first character, inclusive, in this range
- * @param end last character, inclusive, in this range
- * @return the new CharRange object
- * @see CharRange#CharRange(char, char, boolean)
+ *
A negated range includes everything except that defined by the
+ * single character.
+ *
+ * @param ch only character in this range.
+ * @return the new CharRange object.
* @since 2.5
*/
- public static CharRange isIn(final char start, final char end) {
- return new CharRange(start, end, false);
+ public static CharRange isNot(final char ch) {
+ return new CharRange(ch, ch, true);
}
/**
- *
Constructs a negated {@code CharRange} over a set of characters.
+ * Constructs a negated {@link CharRange} over a set of characters.
+ *
+ *
A negated range includes everything except that defined by the
+ * start and end characters.
+ *
+ *
If start and end are in the wrong order, they are reversed.
+ * Thus {@code a-e} is the same as {@code e-a}.
*
- * @param start first character, inclusive, in this range
- * @param end last character, inclusive, in this range
- * @return the new CharRange object
- * @see CharRange#CharRange(char, char, boolean)
+ * @param start first character, inclusive, in this range.
+ * @param end last character, inclusive, in this range.
+ * @return the new CharRange object.
* @since 2.5
*/
public static CharRange isNotIn(final char start, final char end) {
return new CharRange(start, end, true);
}
- // Accessors
- //-----------------------------------------------------------------------
- /**
- *
Gets the start character for this character range.
- *
- * @return the start char (inclusive)
- */
- public char getStart() {
- return this.start;
- }
+ /** The first character, inclusive, in the range. */
+ private final char start;
- /**
- *
Gets the end character for this character range.
- *
- * @return the end char (inclusive)
- */
- public char getEnd() {
- return this.end;
- }
+ /** The last character, inclusive, in the range. */
+ private final char end;
+
+ /** True if the range is everything except the characters specified. */
+ private final boolean negated;
+
+ /** Cached toString. */
+ private transient String iToString;
/**
- *
Is this {@code CharRange} negated.
- *
+ * Constructs a {@link CharRange} over a set of characters,
+ * optionally negating the range.
+ *
*
A negated range includes everything except that defined by the
* start and end characters.
*
- * @return {@code true} if negated
+ *
If start and end are in the wrong order, they are reversed.
+ * Thus {@code a-e} is the same as {@code e-a}.
+ *
+ * @param start first character, inclusive, in this range.
+ * @param end last character, inclusive, in this range.
+ * @param negated true to express everything except the range.
*/
- public boolean isNegated() {
- return negated;
+ private CharRange(char start, char end, final boolean negated) {
+ if (start > end) {
+ final char temp = start;
+ start = end;
+ end = temp;
+ }
+
+ this.start = start;
+ this.end = end;
+ this.negated = negated;
}
- // Contains
- //-----------------------------------------------------------------------
/**
- *
Is the character specified contained in this range.
+ * Is the character specified contained in this range.
*
- * @param ch the character to check
- * @return {@code true} if this range contains the input character
+ * @param ch the character to check.
+ * @return {@code true} if this range contains the input character.
*/
public boolean contains(final char ch) {
return (ch >= start && ch <= end) != negated;
}
/**
- *
Are all the characters of the passed in range contained in
- * this range.
+ * Are all the characters of the passed in range contained in
+ * this range.
*
- * @param range the range to check against
- * @return {@code true} if this range entirely contains the input range
- * @throws IllegalArgumentException if {@code null} input
+ * @param range the range to check against.
+ * @return {@code true} if this range entirely contains the input range.
+ * @throws NullPointerException if {@code null} input.
*/
public boolean contains(final CharRange range) {
- if (range == null) {
- throw new IllegalArgumentException("The Range must not be null");
- }
+ Objects.requireNonNull(range, "range");
if (negated) {
if (range.negated) {
return start >= range.start && end <= range.end;
@@ -194,21 +271,19 @@ public boolean contains(final CharRange range) {
return start <= range.start && end >= range.end;
}
- // Basics
- //-----------------------------------------------------------------------
/**
- *
Compares two CharRange objects, returning true if they represent
- * exactly the same range of characters defined in the same way.
- *
- * @param obj the object to compare to
- * @return true if equal
+ * Compares two CharRange objects, returning true if they represent
+ * exactly the same range of characters defined in the same way.
+ *
+ * @param obj the object to compare to.
+ * @return true if equal.
*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
- if (obj instanceof CharRange == false) {
+ if (!(obj instanceof CharRange)) {
return false;
}
final CharRange other = (CharRange) obj;
@@ -216,43 +291,50 @@ public boolean equals(final Object obj) {
}
/**
- *
Gets a hashCode compatible with the equals method.
- *
- * @return a suitable hashCode
+ * Gets the end character for this character range.
+ *
+ * @return the end char (inclusive).
+ */
+ public char getEnd() {
+ return this.end;
+ }
+
+ /**
+ * Gets the start character for this character range.
+ *
+ * @return the start char (inclusive).
+ */
+ public char getStart() {
+ return this.start;
+ }
+
+ /**
+ * Gets a hashCode compatible with the equals method.
+ *
+ * @return a suitable hashCode.
*/
@Override
public int hashCode() {
- return 83 + start + 7 * end + (negated ? 1 : 0);
+ return Objects.hash(end, negated, start);
}
-
+
/**
- *
Gets a string representation of the character range.
- *
- * @return string representation of this range
+ * Is this {@link CharRange} negated.
+ *
+ *
A negated range includes everything except that defined by the
+ * start and end characters.
+ *
+ * @return {@code true} if negated.
*/
- @Override
- public String toString() {
- if (iToString == null) {
- final StringBuilder buf = new StringBuilder(4);
- if (isNegated()) {
- buf.append('^');
- }
- buf.append(start);
- if (start != end) {
- buf.append('-');
- buf.append(end);
- }
- iToString = buf.toString();
- }
- return iToString;
+ public boolean isNegated() {
+ return negated;
}
- // Expansions
- //-----------------------------------------------------------------------
/**
- *
Returns an iterator which can be used to walk through the characters described by this range.
+ * Returns an iterator which can be used to walk through the characters described by this range.
*
*
#NotThreadSafe# the iterator is not thread-safe
+ *
* @return an iterator to the chars represented by this range
* @since 2.5
*/
@@ -262,98 +344,24 @@ public Iterator iterator() {
}
/**
- * Character {@link Iterator}.
- *
#NotThreadSafe#
+ * Gets a string representation of the character range.
+ *
+ * @return string representation of this range.
*/
- private static class CharacterIterator implements Iterator {
- /** The current character */
- private char current;
-
- private final CharRange range;
- private boolean hasNext;
-
- /**
- * Construct a new iterator for the character range.
- *
- * @param r The character range
- */
- private CharacterIterator(final CharRange r) {
- range = r;
- hasNext = true;
-
- if (range.negated) {
- if (range.start == 0) {
- if (range.end == Character.MAX_VALUE) {
- // This range is an empty set
- hasNext = false;
- } else {
- current = (char) (range.end + 1);
- }
- } else {
- current = 0;
- }
- } else {
- current = range.start;
- }
- }
-
- /**
- * Prepare the next character in the range.
- */
- private void prepareNext() {
- if (range.negated) {
- if (current == Character.MAX_VALUE) {
- hasNext = false;
- } else if (current + 1 == range.start) {
- if (range.end == Character.MAX_VALUE) {
- hasNext = false;
- } else {
- current = (char) (range.end + 1);
- }
- } else {
- current = (char) (current + 1);
- }
- } else if (current < range.end) {
- current = (char) (current + 1);
- } else {
- hasNext = false;
+ @Override
+ public String toString() {
+ if (iToString == null) {
+ final StringBuilder buf = new StringBuilder(4);
+ if (isNegated()) {
+ buf.append('^');
}
- }
-
- /**
- * Has the iterator not reached the end character yet?
- *
- * @return {@code true} if the iterator has yet to reach the character date
- */
- @Override
- public boolean hasNext() {
- return hasNext;
- }
-
- /**
- * Return the next character in the iteration
- *
- * @return {@code Character} for the next character
- */
- @Override
- public Character next() {
- if (hasNext == false) {
- throw new NoSuchElementException();
+ buf.append(start);
+ if (start != end) {
+ buf.append('-');
+ buf.append(end);
}
- final char cur = current;
- prepareNext();
- return Character.valueOf(cur);
- }
-
- /**
- * Always throws UnsupportedOperationException.
- *
- * @throws UnsupportedOperationException
- * @see java.util.Iterator#remove()
- */
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
+ iToString = buf.toString();
}
+ return iToString;
}
}
diff --git a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
index a5112d9d017..9fc1fd84afd 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,8 +17,8 @@
package org.apache.commons.lang3;
/**
- *
Operations on {@link CharSequence} that are
- * {@code null} safe.
+ * Operations on {@link CharSequence} that are
+ * {@code null} safe.
*
* @see CharSequence
* @since 3.0
@@ -27,71 +27,38 @@ public class CharSequenceUtils {
private static final int NOT_FOUND = -1;
- /**
- *
{@code CharSequenceUtils} instances should NOT be constructed in
- * standard programming.
- *
- *
This constructor is public to permit tools that require a JavaBean
- * instance to operate.
Returns a new {@code CharSequence} that is a subsequence of this
- * sequence starting with the {@code char} value at the specified index.
- *
- *
This provides the {@code CharSequence} equivalent to {@link String#substring(int)}.
- * The length (in {@code char}) of the returned sequence is {@code length() - start},
- * so if {@code start == end} then an empty sequence is returned.
- *
- * @param cs the specified subsequence, null returns null
- * @param start the start index, inclusive, valid
- * @return a new subsequence, may be null
- * @throws IndexOutOfBoundsException if {@code start} is negative or if
- * {@code start} is greater than {@code length()}
- */
- public static CharSequence subSequence(final CharSequence cs, final int start) {
- return cs == null ? null : cs.subSequence(start, cs.length());
- }
+ static final int TO_STRING_LIMIT = 16;
- //-----------------------------------------------------------------------
- /**
- *
Finds the first index in the {@code CharSequence} that matches the
- * specified character.
- *
- * @param cs the {@code CharSequence} to be processed, not null
- * @param searchChar the char to be searched for
- * @param start the start index, negative starts at the string start
- * @return the index where the search char was found, -1 if not found
- */
- static int indexOf(final CharSequence cs, final int searchChar, int start) {
- if (cs instanceof String) {
- return ((String) cs).indexOf(searchChar, start);
- }
- final int sz = cs.length();
- if (start < 0) {
- start = 0;
- }
- for (int i = start; i < sz; i++) {
- if (cs.charAt(i) == searchChar) {
- return i;
+ private static boolean checkLaterThan1(final CharSequence cs, final CharSequence searchChar, final int len2, final int start1) {
+ for (int i = 1, j = len2 - 1; i <= j; i++, j--) {
+ if (cs.charAt(start1 + i) != searchChar.charAt(i) || cs.charAt(start1 + j) != searchChar.charAt(j)) {
+ return false;
}
}
- return NOT_FOUND;
+ return true;
}
/**
* Used by the indexOf(CharSequence methods) as a green implementation of indexOf.
*
- * @param cs the {@code CharSequence} to be processed
- * @param searchChar the {@code CharSequence} to be searched for
- * @param start the start index
- * @return the index where the search sequence was found
+ * @param cs the {@link CharSequence} to be processed.
+ * @param searchChar the {@link CharSequence} to be searched for.
+ * @param start the start index.
+ * @return the index where the search sequence was found, or {@code -1} if there is no such occurrence.
*/
static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
+ if (cs == null || searchChar == null) {
+ return StringUtils.INDEX_NOT_FOUND;
+ }
+ if (cs instanceof String) {
+ return ((String) cs).indexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).indexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).indexOf(searchChar.toString(), start);
+ }
return cs.toString().indexOf(searchChar.toString(), start);
// if (cs instanceof String && searchChar instanceof String) {
// // TODO: Do we assume searchChar is usually relatively small;
@@ -105,28 +72,66 @@ static int indexOf(final CharSequence cs, final CharSequence searchChar, final i
}
/**
- *
Finds the last index in the {@code CharSequence} that matches the
- * specified character.
+ * Returns the index within {@code cs} of the first occurrence of the specified character, starting the search at the specified index.
+ *
+ * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code cs} object at an index no smaller than
+ * {@code start}, then the index of the first such occurrence is returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this
+ * is the smallest value k such that:
+ *
+ * is true. For other values of {@code searchChar}, it is the smallest value k such that:
+ *
*
- * @param cs the {@code CharSequence} to be processed
- * @param searchChar the char to be searched for
- * @param start the start index, negative returns -1, beyond length starts at end
- * @return the index where the search char was found, -1 if not found
+ *
+ * is true. In either case, if no such character occurs inm {@code cs} at or after position {@code start}, then {@code -1} is returned.
+ *
+ *
+ * There is no restriction on the value of {@code start}. If it is negative, it has the same effect as if it were zero: the entire {@link CharSequence} may
+ * be searched. If it is greater than the length of {@code cs}, it has the same effect as if it were equal to the length of {@code cs}: {@code -1} is
+ * returned.
+ *
+ *
+ * All indices are specified in {@code char} values (Unicode code units).
+ *
+ *
+ * @param cs the {@link CharSequence} to be processed, not null.
+ * @param searchChar the char to be searched for.
+ * @param start the start index, negative starts at the string start.
+ * @return the index where the search char was found, -1 if not found.
+ * @since 3.6 updated to behave more like {@link String}.
*/
- static int lastIndexOf(final CharSequence cs, final int searchChar, int start) {
+ static int indexOf(final CharSequence cs, final int searchChar, int start) {
if (cs instanceof String) {
- return ((String) cs).lastIndexOf(searchChar, start);
+ return ((String) cs).indexOf(searchChar, start);
}
final int sz = cs.length();
if (start < 0) {
- return NOT_FOUND;
+ start = 0;
}
- if (start >= sz) {
- start = sz - 1;
+ if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+ for (int i = start; i < sz; i++) {
+ if (cs.charAt(i) == searchChar) {
+ return i;
+ }
+ }
+ return NOT_FOUND;
}
- for (int i = start; i >= 0; --i) {
- if (cs.charAt(i) == searchChar) {
- return i;
+ //supplementary characters (LANG1300)
+ if (searchChar <= Character.MAX_CODE_POINT) {
+ final char[] chars = Character.toChars(searchChar);
+ for (int i = start; i < sz - 1; i++) {
+ final char high = cs.charAt(i);
+ final char low = cs.charAt(i + 1);
+ if (high == chars[0] && low == chars[1]) {
+ return i;
+ }
}
}
return NOT_FOUND;
@@ -135,95 +140,256 @@ static int lastIndexOf(final CharSequence cs, final int searchChar, int start) {
/**
* Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf
*
- * @param cs the {@code CharSequence} to be processed
- * @param searchChar the {@code CharSequence} to be searched for
- * @param start the start index
- * @return the index where the search sequence was found
+ * @param cs the {@link CharSequence} to be processed.
+ * @param searchChar the {@link CharSequence} to find.
+ * @param start the start index.
+ * @return the index where the search sequence was found.
*/
- static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
- return cs.toString().lastIndexOf(searchChar.toString(), start);
-// if (cs instanceof String && searchChar instanceof String) {
-// // TODO: Do we assume searchChar is usually relatively small;
-// // If so then calling toString() on it is better than reverting to
-// // the green implementation in the else block
-// return ((String) cs).lastIndexOf((String) searchChar, start);
-// } else {
-// // TODO: Implement rather than convert to String
-// return cs.toString().lastIndexOf(searchChar.toString(), start);
-// }
+ static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, int start) {
+ if (searchChar == null || cs == null) {
+ return NOT_FOUND;
+ }
+ if (searchChar instanceof String) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf((String) searchChar, start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
+ }
+ }
+
+ final int len1 = cs.length();
+ final int len2 = searchChar.length();
+
+ if (start > len1) {
+ start = len1;
+ }
+
+ if (start < 0 || len2 > len1) {
+ return NOT_FOUND;
+ }
+
+ if (len2 == 0) {
+ return start;
+ }
+
+ if (len2 <= TO_STRING_LIMIT) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ }
+
+ if (start + len2 > len1) {
+ start = len1 - len2;
+ }
+
+ final char char0 = searchChar.charAt(0);
+
+ int i = start;
+ while (true) {
+ while (cs.charAt(i) != char0) {
+ i--;
+ if (i < 0) {
+ return NOT_FOUND;
+ }
+ }
+ if (checkLaterThan1(cs, searchChar, len2, i)) {
+ return i;
+ }
+ i--;
+ if (i < 0) {
+ return NOT_FOUND;
+ }
+ }
}
/**
- * Green implementation of toCharArray.
+ * Returns the index within {@code cs} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
+ * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value k such that:
+ *
+ *
+ * is true. In either case, if no such character occurs in {@code cs} at or before position {@code start}, then {@code -1} is returned.
+ *
+ *
+ * All indices are specified in {@code char} values (Unicode code units).
+ *
+ *
+ * @param cs the {@link CharSequence} to be processed.
+ * @param searchChar the char to be searched for.
+ * @param start the start index, negative returns -1, beyond length starts at end.
+ * @return the index where the search char was found, -1 if not found.
+ * @since 3.6 updated to behave more like {@link String}.
*/
- static char[] toCharArray(final CharSequence cs) {
+ static int lastIndexOf(final CharSequence cs, final int searchChar, int start) {
if (cs instanceof String) {
- return ((String) cs).toCharArray();
+ return ((String) cs).lastIndexOf(searchChar, start);
}
final int sz = cs.length();
- final char[] array = new char[cs.length()];
- for (int i = 0; i < sz; i++) {
- array[i] = cs.charAt(i);
+ if (start < 0) {
+ return NOT_FOUND;
}
- return array;
+ if (start >= sz) {
+ start = sz - 1;
+ }
+ if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+ for (int i = start; i >= 0; --i) {
+ if (cs.charAt(i) == searchChar) {
+ return i;
+ }
+ }
+ return NOT_FOUND;
+ }
+ //supplementary characters (LANG1300)
+ //NOTE - we must do a forward traversal for this to avoid duplicating code points
+ if (searchChar <= Character.MAX_CODE_POINT) {
+ final char[] chars = Character.toChars(searchChar);
+ //make sure it's not the last index
+ if (start == sz - 1) {
+ return NOT_FOUND;
+ }
+ for (int i = start; i >= 0; i--) {
+ final char high = cs.charAt(i);
+ final char low = cs.charAt(i + 1);
+ if (chars[0] == high && chars[1] == low) {
+ return i;
+ }
+ }
+ }
+ return NOT_FOUND;
}
/**
- * Green implementation of regionMatches.
+ * Tests if two string regions are equal.
*
- * @param cs the {@code CharSequence} to be processed
- * @param ignoreCase whether or not to be case insensitive
- * @param thisStart the index to start on the {@code cs} CharSequence
- * @param substring the {@code CharSequence} to be looked for
- * @param start the index to start on the {@code substring} CharSequence
- * @param length character length of the region
- * @return whether the region matched
+ * @param cs the {@link CharSequence} to be processed.
+ * @param ignoreCase whether or not to be case-insensitive.
+ * @param thisStart the index to start on the {@code cs} CharSequence.
+ * @param substring the {@link CharSequence} to be looked for.
+ * @param start the index to start on the {@code substring} CharSequence.
+ * @param length character length of the region.
+ * @return whether the region matched.
+ * @see String#regionMatches(boolean, int, String, int, int)
*/
- static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
- final CharSequence substring, final int start, final int length) {
+ static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, final CharSequence substring, final int start,
+ final int length) {
+ // Green implementation of regionMatches.
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
}
int index1 = thisStart;
int index2 = start;
int tmpLen = length;
-
// Extract these first so we detect NPEs the same as the java.lang.String version
final int srcLen = cs.length() - thisStart;
final int otherLen = substring.length() - start;
-
// Check for invalid parameters
if (thisStart < 0 || start < 0 || length < 0) {
return false;
}
-
// Check that the regions are long enough
if (srcLen < length || otherLen < length) {
return false;
}
-
while (tmpLen-- > 0) {
final char c1 = cs.charAt(index1++);
final char c2 = substring.charAt(index2++);
-
if (c1 == c2) {
continue;
}
-
if (!ignoreCase) {
return false;
}
-
- // The same check as in String.regionMatches():
- if (Character.toUpperCase(c1) != Character.toUpperCase(c2)
- && Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
+ // The real same check as in String#regionMatches(boolean, int, String, int, int):
+ final char u1 = Character.toUpperCase(c1);
+ final char u2 = Character.toUpperCase(c2);
+ if (u1 != u2 && Character.toLowerCase(u1) != Character.toLowerCase(u2)) {
return false;
}
}
-
return true;
}
+
+ /**
+ * Returns a new {@link CharSequence} that is a subsequence of this
+ * sequence starting with the {@code char} value at the specified index.
+ *
+ *
This provides the {@link CharSequence} equivalent to {@link String#substring(int)}.
+ * The length (in {@code char}) of the returned sequence is {@code length() - start},
+ * so if {@code start == end} then an empty sequence is returned.
+ *
+ * @param cs the specified subsequence, null returns null.
+ * @param start the start index, inclusive, valid.
+ * @return a new subsequence, may be null.
+ * @throws IndexOutOfBoundsException if {@code start} is negative or if
+ * {@code start} is greater than {@code length()}.
+ */
+ public static CharSequence subSequence(final CharSequence cs, final int start) {
+ return cs == null ? null : cs.subSequence(start, cs.length());
+ }
+
+ /**
+ * Converts the given CharSequence to a char[].
+ *
+ * @param source the {@link CharSequence} to be processed.
+ * @return the resulting char array, never null.
+ * @since 3.11
+ */
+ public static char[] toCharArray(final CharSequence source) {
+ // See CharSequenceUtilsBenchmark
+ final int len = StringUtils.length(source);
+ if (len == 0) {
+ return ArrayUtils.EMPTY_CHAR_ARRAY;
+ }
+ if (source instanceof String) {
+ return ((String) source).toCharArray();
+ }
+ if (source instanceof StringBuilder) {
+ final char[] array = new char[len];
+ ((StringBuilder) source).getChars(0, len, array, 0);
+ return array;
+ }
+ if (source instanceof StringBuffer) {
+ final char[] array = new char[len];
+ ((StringBuffer) source).getChars(0, len, array, 0);
+ return array;
+ }
+ final char[] array = new char[len];
+ for (int i = 0; i < len; i++) {
+ array[i] = source.charAt(i);
+ }
+ return array;
+ }
+
+ /**
+ * {@link CharSequenceUtils} instances should NOT be constructed in
+ * standard programming.
+ *
+ *
This constructor is public to permit tools that require a JavaBean
+ * instance to operate.
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public CharSequenceUtils() {
+ // empty
+ }
}
diff --git a/src/main/java/org/apache/commons/lang3/CharSet.java b/src/main/java/org/apache/commons/lang3/CharSet.java
index 2cd4c7bdeb4..bdbffc4c48f 100644
--- a/src/main/java/org/apache/commons/lang3/CharSet.java
+++ b/src/main/java/org/apache/commons/lang3/CharSet.java
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,67 +19,77 @@
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Stream;
/**
- *
A set of characters.
+ * A set of characters.
*
*
Instances are immutable, but instances of subclasses may not be.
*
*
#ThreadSafe#
+ *
* @since 1.0
*/
public class CharSet implements Serializable {
/**
- * Required for serialization support. Lang version 2.0.
- *
+ * Required for serialization support. Lang version 2.0.
+ *
* @see java.io.Serializable
*/
private static final long serialVersionUID = 5947847346149275958L;
- /**
- * A CharSet defining no characters.
+ /**
+ * A CharSet defining no characters.
+ *
* @since 2.0
*/
public static final CharSet EMPTY = new CharSet((String) null);
- /**
+ /**
* A CharSet defining ASCII alphabetic characters "a-zA-Z".
+ *
* @since 2.0
*/
public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z");
- /**
+ /**
* A CharSet defining ASCII alphabetic characters "a-z".
+ *
* @since 2.0
*/
public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z");
- /**
+ /**
* A CharSet defining ASCII alphabetic characters "A-Z".
+ *
* @since 2.0
*/
public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z");
- /**
+ /**
* A CharSet defining ASCII alphabetic characters "0-9".
+ *
* @since 2.0
*/
public static final CharSet ASCII_NUMERIC = new CharSet("0-9");
/**
* A Map of the common cases used in the factory.
- * Subclasses can add more common patterns if desired
+ *
+ * Subclasses can add more common patterns if desired.
+ *
+ *
* @since 2.0
*/
- protected static final Map COMMON = Collections.synchronizedMap(new HashMap());
-
+ protected static final Map COMMON = Collections.synchronizedMap(new HashMap<>());
+
static {
COMMON.put(null, EMPTY);
- COMMON.put("", EMPTY);
+ COMMON.put(StringUtils.EMPTY, EMPTY);
COMMON.put("a-zA-Z", ASCII_ALPHA);
COMMON.put("A-Za-z", ASCII_ALPHA);
COMMON.put("a-z", ASCII_ALPHA_LOWER);
@@ -87,12 +97,8 @@ public class CharSet implements Serializable {
COMMON.put("0-9", ASCII_NUMERIC);
}
- /** The set of CharRange objects. */
- private final Set set = Collections.synchronizedSet(new HashSet());
-
- //-----------------------------------------------------------------------
/**
- *
Factory method to create a new CharSet using a special syntax.
+ * Creates a new CharSet using the syntax described below.
*
*
*
{@code null} or empty string ("")
@@ -109,12 +115,12 @@ public class CharSet implements Serializable {
*
*
The matching order is:
*
- *
Negated multi character range, such as "^a-e"
- *
Ordinary multi character range, such as "a-e"
- *
Negated single character, such as "^a"
- *
Ordinary single character, such as "a"
+ *
Negated multi character range, such as "^a-e"
+ *
Ordinary multi character range, such as "a-e"
+ *
Negated single character, such as "^a"
+ *
Ordinary single character, such as "a"
*
- *
+ *
*
Matching works left to right. Once a match is found the
* search starts again from the next character.
*
@@ -128,11 +134,11 @@ public class CharSet implements Serializable {
* as the "a-e" and "e-a" are the same.
*
*
The set of characters represented is the union of the specified ranges.
- *
+ *
*
There are two ways to add a literal negation character ({@code ^}):
*
*
As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
- *
As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
+ *
As a separate element, e.g. {@code CharSet.getInstance("^", "a-z")}
All CharSet objects returned by this method will be immutable.
*
- * @param setStrs Strings to merge into the set, may be null
- * @return a CharSet instance
+ * @param setStrs Strings to merge into the set, may be null.
+ * @return a CharSet instance.
* @since 2.4
*/
public static CharSet getInstance(final String... setStrs) {
if (setStrs == null) {
- return null;
+ return EMPTY;
}
if (setStrs.length == 1) {
final CharSet common = COMMON.get(setStrs[0]);
@@ -162,28 +168,25 @@ public static CharSet getInstance(final String... setStrs) {
return common;
}
}
- return new CharSet(setStrs);
+ return new CharSet(setStrs);
}
- //-----------------------------------------------------------------------
+ /** The set of CharRange objects. */
+ private final Set set = Collections.synchronizedSet(new LinkedHashSet<>());
+
/**
- *
Constructs a new CharSet using the set syntax.
- * Each string is merged in with the set.
+ * Constructs a new CharSet using the set syntax.
+ * Each string is merged in with the set.
*
- * @param set Strings to merge into the initial set
- * @throws NullPointerException if set is {@code null}
+ * @param set Strings to merge into the initial set.
+ * @throws NullPointerException if set is {@code null}.
*/
protected CharSet(final String... set) {
- super();
- final int sz = set.length;
- for (int i = 0; i < sz; i++) {
- add(set[i]);
- }
+ Stream.of(set).forEach(this::add);
}
- //-----------------------------------------------------------------------
/**
- *
Add a set definition string to the {@code CharSet}.
+ * Add a set definition string to the {@link CharSet}.
*
* @param str set definition string
*/
@@ -191,7 +194,6 @@ protected void add(final String str) {
if (str == null) {
return;
}
-
final int len = str.length();
int pos = 0;
while (pos < len) {
@@ -216,47 +218,39 @@ protected void add(final String str) {
}
}
- //-----------------------------------------------------------------------
/**
- *
Gets the internal set as an array of CharRange objects.
- *
- * @return an array of immutable CharRange objects
- * @since 2.0
- */
-// NOTE: This is no longer public as CharRange is no longer a public class.
-// It may be replaced when CharSet moves to Range.
- /*public*/ CharRange[] getCharRanges() {
- return set.toArray(new CharRange[set.size()]);
- }
-
- //-----------------------------------------------------------------------
- /**
- *
Does the {@code CharSet} contain the specified
- * character {@code ch}.
+ * Tests whether this {@link CharSet} contain the specified character {@code ch}.
+ *
*
- * @param ch the character to check for
- * @return {@code true} if the set contains the characters
+ * @param ch the character to check.
+ * @return {@code true} if the set contains the characters.
*/
public boolean contains(final char ch) {
- for (final CharRange range : set) {
- if (range.contains(ch)) {
- return true;
- }
+ synchronized (set) {
+ return set.stream().anyMatch(range -> range.contains(ch));
}
- return false;
}
- // Basics
- //-----------------------------------------------------------------------
/**
- *
Compares two {@code CharSet} objects, returning true if they represent
- * exactly the same set of characters defined in the same way.
+ * Compares two {@link CharSet} objects, returning true if they represent
+ * exactly the same set of characters defined in the same way.
*
- *
The two sets {@code abc} and {@code a-c} are not
+ *
The two sets {@code abc} and {@code a-c} are not
* equal according to this method.
*
- * @param obj the object to compare to
- * @return true if equal
+ * @param obj the object to compare.
+ * @return true if equal.
* @since 2.0
*/
@Override
@@ -264,7 +258,7 @@ public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
- if (obj instanceof CharSet == false) {
+ if (!(obj instanceof CharSet)) {
return false;
}
final CharSet other = (CharSet) obj;
@@ -272,9 +266,21 @@ public boolean equals(final Object obj) {
}
/**
- *
Gets a hash code compatible with the equals method.
+ * Gets the set of character ranges.
+ *
+ * Package private for testing.
+ *
+ *
+ * @return the set of character ranges.
+ */
+ Set getCharRanges() {
+ return set;
+ }
+
+ /**
+ * Gets a hash code compatible with the equals method.
*
- * @return a suitable hash code
+ * @return a suitable hash code.
* @since 2.0
*/
@Override
@@ -283,9 +289,9 @@ public int hashCode() {
}
/**
- *
Gets a string representation of the set.
+ * Gets a string representation of the set.
*
- * @return string representation of the set
+ * @return string representation of the set.
*/
@Override
public String toString() {
diff --git a/src/main/java/org/apache/commons/lang3/CharSetUtils.java b/src/main/java/org/apache/commons/lang3/CharSetUtils.java
index 859967410fd..d8dd4aa2124 100644
--- a/src/main/java/org/apache/commons/lang3/CharSetUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSetUtils.java
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,77 +16,25 @@
*/
package org.apache.commons.lang3;
+import org.apache.commons.lang3.stream.Streams;
+
/**
- *
Operations on {@code CharSet} instances.
+ * Operations on {@link CharSet} instances.
*
*
This class handles {@code null} input gracefully.
* An exception will not be thrown for a {@code null} input.
- * Each method documents its behaviour in more detail.
- *
+ * Each method documents its behavior in more detail.
+ *
*
#ThreadSafe#
+ *
* @see CharSet
* @since 1.0
*/
public class CharSetUtils {
/**
- *
CharSetUtils instances should NOT be constructed in standard programming.
- * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.
- *
- *
This constructor is public to permit tools that require a JavaBean instance
- * to operate.
*
- * @see CharSet#getInstance(java.lang.String...) for set-syntax.
+ * @see CharSet#getInstance(String...) for set-syntax.
* @param str String to look for characters in, may be null
* @param set String[] set of characters to identify, may be null
* @return whether or not the characters in the set are in the primary string
* @since 3.2
*/
public static boolean containsAny(final String str, final String... set) {
- if (StringUtils.isEmpty(str) || deepEmpty(set)) {
+ if (isEmpty(str, set)) {
return false;
}
final CharSet chars = CharSet.getInstance(set);
@@ -116,11 +64,9 @@ public static boolean containsAny(final String str, final String... set) {
return false;
}
- // Count
- //-----------------------------------------------------------------------
/**
- *
Takes an argument in set-syntax, see evaluateSet,
- * and returns the number of characters present in the specified string.
+ * Takes an argument in set-syntax, see evaluateSet,
+ * and returns the number of characters present in the specified string.
*
*
*
- * @see CharSet#getInstance(java.lang.String...) for set-syntax.
+ * @see CharSet#getInstance(String...) for set-syntax.
* @param str String to count characters in, may be null
* @param set String[] set of characters to count, may be null
* @return the character count, zero if null string input
*/
public static int count(final String str, final String... set) {
- if (StringUtils.isEmpty(str) || deepEmpty(set)) {
+ if (isEmpty(str, set)) {
return 0;
}
final CharSet chars = CharSet.getInstance(set);
@@ -150,42 +96,20 @@ public static int count(final String str, final String... set) {
return count;
}
- // Keep
- //-----------------------------------------------------------------------
/**
- *
Takes an argument in set-syntax, see evaluateSet,
- * and keeps any of characters present in the specified string.
+ * Determines whether or not all the Strings in an array are
+ * empty or not.
*
- * @see CharSet#getInstance(java.lang.String...) for set-syntax.
- * @param str String to keep characters from, may be null
- * @param set String[] set of characters to keep, may be null
- * @return the modified String, {@code null} if null string input
- * @since 2.0
+ * @param strings String[] whose elements are being checked for emptiness
+ * @return whether or not the String is empty
*/
- public static String keep(final String str, final String... set) {
- if (str == null) {
- return null;
- }
- if (str.isEmpty() || deepEmpty(set)) {
- return StringUtils.EMPTY;
- }
- return modify(str, set, true);
+ private static boolean deepEmpty(final String[] strings) {
+ return Streams.of(strings).allMatch(StringUtils::isEmpty);
}
- // Delete
- //-----------------------------------------------------------------------
/**
- *
Takes an argument in set-syntax, see evaluateSet,
- * and deletes any of characters present in the specified string.
+ * Takes an argument in set-syntax, see evaluateSet,
+ * and deletes any of characters present in the specified string.
*
*
*
- * @see CharSet#getInstance(java.lang.String...) for set-syntax.
+ * @see CharSet#getInstance(String...) for set-syntax.
* @param str String to delete characters from, may be null
* @param set String[] set of characters to delete, may be null
* @return the modified String, {@code null} if null string input
*/
public static String delete(final String str, final String... set) {
- if (StringUtils.isEmpty(str) || deepEmpty(set)) {
+ if (isEmpty(str, set)) {
return str;
}
return modify(str, set, false);
}
- //-----------------------------------------------------------------------
+ private static boolean isEmpty(final String str, final String... set) {
+ return StringUtils.isEmpty(str) || deepEmpty(set);
+ }
+
+ /**
+ * Takes an argument in set-syntax, see evaluateSet,
+ * and keeps any of characters present in the specified string.
+ *
+ *
+ *
+ * @see CharSet#getInstance(String...) for set-syntax.
+ * @param str String to keep characters from, may be null
+ * @param set String[] set of characters to keep, may be null
+ * @return the modified String, {@code null} if null string input
+ * @since 2.0
+ */
+ public static String keep(final String str, final String... set) {
+ if (str == null) {
+ return null;
+ }
+ if (str.isEmpty() || deepEmpty(set)) {
+ return StringUtils.EMPTY;
+ }
+ return modify(str, set, true);
+ }
+
/**
- * Implementation of delete and keep
+ * Implements delete and keep.
*
* @param str String to modify characters within
* @param set String[] set of characters to modify
@@ -221,30 +177,75 @@ private static String modify(final String str, final String[] set, final boolean
final CharSet chars = CharSet.getInstance(set);
final StringBuilder buffer = new StringBuilder(str.length());
final char[] chrs = str.toCharArray();
- final int sz = chrs.length;
- for(int i=0; i
+ * CharSetUtils.squeeze(null, *) = null
+ * CharSetUtils.squeeze("", *) = ""
+ * CharSetUtils.squeeze(*, null) = *
+ * CharSetUtils.squeeze(*, "") = *
+ * CharSetUtils.squeeze("hello", "k-p") = "helo"
+ * CharSetUtils.squeeze("hello", "a-e") = "hello"
+ *
+ *
+ * @see CharSet#getInstance(String...) for set-syntax.
+ * @param str the string to squeeze, may be null
+ * @param set the character set to use for manipulation, may be null
+ * @return the modified String, {@code null} if null string input
*/
- private static boolean deepEmpty(final String[] strings) {
- if (strings != null) {
- for (final String s : strings) {
- if (StringUtils.isNotEmpty(s)) {
- return false;
+ public static String squeeze(final String str, final String... set) {
+ if (isEmpty(str, set)) {
+ return str;
+ }
+ final CharSet chars = CharSet.getInstance(set);
+ final StringBuilder buffer = new StringBuilder(str.length());
+ final char[] chrs = str.toCharArray();
+ final int sz = chrs.length;
+ char lastChar = chrs[0];
+ char ch;
+ Character inChars = null;
+ Character notInChars = null;
+ buffer.append(lastChar);
+ for (int i = 1; i < sz; i++) {
+ ch = chrs[i];
+ if (ch == lastChar) {
+ if (inChars != null && ch == inChars) {
+ continue;
+ }
+ if (notInChars == null || ch != notInChars) {
+ if (chars.contains(ch)) {
+ inChars = ch;
+ continue;
+ }
+ notInChars = ch;
}
}
+ buffer.append(ch);
+ lastChar = ch;
}
- return true;
+ return buffer.toString();
+ }
+
+ /**
+ * CharSetUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.
+ *
+ *
This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public CharSetUtils() {
}
}
diff --git a/src/main/java/org/apache/commons/lang3/CharUtils.java b/src/main/java/org/apache/commons/lang3/CharUtils.java
index 3e957411557..fda1bf6184e 100644
--- a/src/main/java/org/apache/commons/lang3/CharUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharUtils.java
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,127 +16,274 @@
*/
package org.apache.commons.lang3;
+import java.util.Objects;
+
/**
- *
Operations on char primitives and Character objects.
+ * Operations on char primitives and Character objects.
*
*
This class tries to handle {@code null} input gracefully.
* An exception will not be thrown for a {@code null} input.
- * Each method documents its behaviour in more detail.
- *
+ * Each method documents its behavior in more detail.
+ *
*
#ThreadSafe#
+ *
* @since 2.1
*/
public class CharUtils {
-
- private static final String[] CHAR_STRING_ARRAY = new String[128];
-
- private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+
+ private static final String[] CHAR_STRING_ARRAY = ArrayUtils.setAll(new String[128], i -> String.valueOf((char) i));
+
+ private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
- * {@code \u000a} linefeed LF ('\n').
- *
- * @see JLF: Escape Sequences
+ * Linefeed character LF ({@code '\n'}, Unicode 000a).
+ *
+ * @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
public static final char LF = '\n';
/**
- * {@code \u000d} carriage return CR ('\r').
- *
- * @see JLF: Escape Sequences
+ * Carriage return character CR ('\r', Unicode 000d).
+ *
+ * @see JLF: Escape Sequences
* for Character and String Literals
* @since 2.2
*/
public static final char CR = '\r';
-
- static {
- for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
- CHAR_STRING_ARRAY[c] = String.valueOf(c);
- }
+ /**
+ * {@code \u0000} null control character ('\0'), abbreviated NUL.
+ *
+ * @since 3.6
+ */
+ public static final char NUL = '\0';
+
+ /**
+ * Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
+ *
+ * @param x the first {@code char} to compare
+ * @param y the second {@code char} to compare
+ * @return the value {@code 0} if {@code x == y};
+ * a value less than {@code 0} if {@code x < y}; and
+ * a value greater than {@code 0} if {@code x > y}
+ * @since 3.4
+ */
+ public static int compare(final char x, final char y) {
+ return x - y;
}
/**
- *
{@code CharUtils} instances should NOT be constructed in standard programming.
- * Instead, the class should be used as {@code CharUtils.toString('c');}.
+ * Tests whether the character is ASCII 7 bit.
*
- *
This constructor is public to permit tools that require a JavaBean instance
- * to operate.
*
- * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
- * @param ch the character to convert
- * @return a Character of the specified character
+ * @param ch the character to check
+ * @return true if between 65 and 90 or 97 and 122 inclusive
*/
- @Deprecated
- public static Character toCharacterObject(final char ch) {
- return Character.valueOf(ch);
+ public static boolean isAsciiAlpha(final char ch) {
+ return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch);
}
-
+
/**
- *
Converts the String to a Character using the first character, returning
- * null for empty Strings.
- *
- *
For ASCII 7 bit characters, this uses a cache that will return the
- * same Character object each time.
- *
+ * Tests whether the character is ASCII 7 bit alphabetic lower case.
+ *
*
*
- * @param str the character to convert
- * @return the Character value of the first letter of the String
+ * @param ch the character to check
+ * @return true if between 97 and 122 inclusive
*/
- public static Character toCharacterObject(final String str) {
- if (StringUtils.isEmpty(str)) {
- return null;
- }
- return Character.valueOf(str.charAt(0));
+ public static boolean isAsciiAlphaLower(final char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit alphanumeric character.
+ *
+ *
+ *
+ * @param ch the character to check
+ * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
+ */
+ public static boolean isAsciiAlphanumeric(final char ch) {
+ return isAsciiAlpha(ch) || isAsciiNumeric(ch);
+ }
+
+ /**
+ * Tests whether the character is ASCII 7 bit alphabetic upper case.
+ *
+ *
+ *
+ * @param ch the character to test.
+ * @return true if character is a hexadecimal character.
+ * @since 3.18.0
+ */
+ public static boolean isHex(final char ch) {
+ return isAsciiNumeric(ch) || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
+ }
+
+ /**
+ * Tests if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
+ *
+ * @param ch the char to check
+ * @return true if the given char is the character representation of one of the digits from 0 to 7
+ * @since 3.18.0
+ */
+ public static boolean isOctal(final char ch) {
+ return ch >= '0' && ch <= '7';
+ }
+
+ /**
+ * Converts the Character to a char throwing an exception for {@code null}.
+ *
*
*
* @param ch the character to convert
* @return the char value of the Character
- * @throws IllegalArgumentException if the Character is null
+ * @throws NullPointerException if the Character is null
*/
public static char toChar(final Character ch) {
- if (ch == null) {
- throw new IllegalArgumentException("The Character must not be null");
- }
- return ch.charValue();
+ return Objects.requireNonNull(ch, "ch").charValue();
}
-
+
/**
- *
Converts the Character to a char handling {@code null}.
- *
+ * Converts the Character to a char handling {@code null}.
+ *
*
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar(' ', 'X') = ' '
@@ -148,39 +295,34 @@ public static char toChar(final Character ch) {
* @return the char value of the Character or the default if null
*/
public static char toChar(final Character ch, final char defaultValue) {
- if (ch == null) {
- return defaultValue;
- }
- return ch.charValue();
+ return ch != null ? ch.charValue() : defaultValue;
}
-
- //-----------------------------------------------------------------------
+
/**
- *
Converts the String to a char using the first character, throwing
- * an exception on empty Strings.
- *
+ * Converts the String to a char using the first character, throwing
+ * an exception on empty Strings.
+ *
*
*
* @param str the character to convert
* @return the char value of the first letter of the String
+ * @throws NullPointerException if the string is null
* @throws IllegalArgumentException if the String is empty
*/
public static char toChar(final String str) {
- if (StringUtils.isEmpty(str)) {
- throw new IllegalArgumentException("The String must not be empty");
- }
+ Validate.notEmpty(str, "The String must not be empty");
return str.charAt(0);
}
-
+
/**
- *
Converts the String to a char using the first character, defaulting
- * the value on empty Strings.
- *
+ * Converts the String to a char using the first character, defaulting
+ * the value on empty Strings.
+ *
*
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar("", 'X') = 'X'
@@ -193,18 +335,47 @@ public static char toChar(final String str) {
* @return the char value of the first letter of the String or the default if null
*/
public static char toChar(final String str, final char defaultValue) {
- if (StringUtils.isEmpty(str)) {
- return defaultValue;
- }
- return str.charAt(0);
+ return StringUtils.isEmpty(str) ? defaultValue : str.charAt(0);
+ }
+
+ /**
+ * Delegates to {@link Character#valueOf(char)}.
+ *
+ * @param c the character to convert
+ * @return a {@code Character} representing {@code c}.
+ * @deprecated Use {@link Character#valueOf(char)}.
+ */
+ @Deprecated
+ public static Character toCharacterObject(final char c) {
+ return Character.valueOf(c);
+ }
+
+ /**
+ * Converts the String to a Character using the first character, returning
+ * null for empty Strings.
+ *
+ *
For ASCII 7 bit characters, this uses a cache that will return the
+ * same Character object each time.
+ *
+ * @param str the character to convert
+ * @return the Character value of the first letter of the String
+ */
+ public static Character toCharacterObject(final String str) {
+ return StringUtils.isEmpty(str) ? null : Character.valueOf(str.charAt(0));
}
-
- //-----------------------------------------------------------------------
+
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
- *
- *
This method coverts the char '1' to the int 1 and so on.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
+ *
+ *
This method converts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue('3') = 3
@@ -216,17 +387,17 @@ public static char toChar(final String str, final char defaultValue) {
* @throws IllegalArgumentException if the character is not ASCII numeric
*/
public static int toIntValue(final char ch) {
- if (isAsciiNumeric(ch) == false) {
+ if (!isAsciiNumeric(ch)) {
throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
}
return ch - 48;
}
-
+
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
- *
- *
This method coverts the char '1' to the int 1 and so on.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
+ *
+ *
This method converts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue('3', -1) = 3
@@ -238,40 +409,35 @@ public static int toIntValue(final char ch) {
* @return the int value of the character
*/
public static int toIntValue(final char ch, final int defaultValue) {
- if (isAsciiNumeric(ch) == false) {
- return defaultValue;
- }
- return ch - 48;
+ return isAsciiNumeric(ch) ? ch - 48 : defaultValue;
}
-
+
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
- *
- *
This method coverts the char '1' to the int 1 and so on.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
+ *
+ *
This method converts the char '1' to the int 1 and so on.
*
* @param ch the character to convert, not null
* @return the int value of the character
- * @throws IllegalArgumentException if the Character is not ASCII numeric or is null
+ * @throws NullPointerException if the Character is null
+ * @throws IllegalArgumentException if the Character is not ASCII numeric
*/
public static int toIntValue(final Character ch) {
- if (ch == null) {
- throw new IllegalArgumentException("The character must not be null");
- }
- return toIntValue(ch.charValue());
+ return toIntValue(toChar(ch));
}
-
+
/**
- *
Converts the character to the Integer it represents, throwing an
- * exception if the character is not numeric.
- *
- *
This method coverts the char '1' to the int 1 and so on.
+ * Converts the character to the Integer it represents, throwing an
+ * exception if the character is not numeric.
+ *
+ *
This method converts the char '1' to the int 1 and so on.
*
*
* CharUtils.toIntValue(null, -1) = -1
@@ -284,16 +450,12 @@ public static int toIntValue(final Character ch) {
* @return the int value of the character
*/
public static int toIntValue(final Character ch, final int defaultValue) {
- if (ch == null) {
- return defaultValue;
- }
- return toIntValue(ch.charValue(), defaultValue);
+ return ch != null ? toIntValue(ch.charValue(), defaultValue) : defaultValue;
}
-
- //-----------------------------------------------------------------------
+
/**
- *
Converts the character to a String that contains the one character.
- *
+ * Converts the character to a String that contains the one character.
+ *
*
For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
*
@@ -306,18 +468,18 @@ public static int toIntValue(final Character ch, final int defaultValue) {
* @return a String containing the one specified character
*/
public static String toString(final char ch) {
- if (ch < 128) {
+ if (ch < CHAR_STRING_ARRAY.length) {
return CHAR_STRING_ARRAY[ch];
}
- return new String(new char[] {ch});
+ return String.valueOf(ch);
}
-
+
/**
- *
Converts the character to a String that contains the one character.
- *
+ * Converts the character to a String that contains the one character.
+ *
*
For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.
- *
+ *
*
If {@code null} is passed in, {@code null} will be returned.
*
*
@@ -330,41 +492,35 @@ public static String toString(final char ch) {
* @return a String containing the one specified character
*/
public static String toString(final Character ch) {
- if (ch == null) {
- return null;
- }
- return toString(ch.charValue());
+ return ch != null ? toString(ch.charValue()) : null;
}
-
- //--------------------------------------------------------------------------
+
/**
- *
Converts the string to the Unicode format '\u0020'.
- *
+ * Converts the string to the Unicode format '\u0020'.
+ *
*
- *
- * @param ch the character to check
- * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
- */
- public static boolean isAsciiAlphanumeric(final char ch) {
- return isAsciiAlpha(ch) || isAsciiNumeric(ch);
+ return ch != null ? unicodeEscaped(ch.charValue()) : null;
}
/**
- *
Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.
+ * {@link CharUtils} instances should NOT be constructed in standard programming.
+ * Instead, the class should be used as {@code CharUtils.toString('c');}.
*
- * @param x the first {@code char} to compare
- * @param y the second {@code char} to compare
- * @return the value {@code 0} if {@code x == y};
- * a value less than {@code 0} if {@code x < y}; and
- * a value greater than {@code 0} if {@code x > y}
- * @since 3.4
+ *
This constructor is public to permit tools that require a JavaBean instance
+ * to operate.
+ *
+ * @deprecated TODO Make private in 4.0.
*/
- public static int compare(char x, char y) {
- return x-y;
+ @Deprecated
+ public CharUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/Charsets.java b/src/main/java/org/apache/commons/lang3/Charsets.java
new file mode 100644
index 00000000000..4db73473f20
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/Charsets.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3;
+
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * Internal use only.
+ *
+ * Provides utilities for {@link Charset}.
+ *
+ *
+ * Package private since Apache Commons IO already provides a Charsets because {@link Charset} is in
+ * {@code java.nio.charset}.
+ *
+ *
+ * @since 3.10
+ */
+final class Charsets {
+
+ /**
+ * Returns the given {@code charset} or the default Charset if {@code charset} is null.
+ *
+ * @param charset a Charset or null.
+ * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ */
+ static Charset toCharset(final Charset charset) {
+ return charset == null ? Charset.defaultCharset() : charset;
+ }
+
+ /**
+ * Returns the given {@code charset} or the default Charset if {@code charset} is null.
+ *
+ * @param charsetName a Charset or null.
+ * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ * @throws UnsupportedCharsetException If no support for the named charset is available in this instance of the Java
+ * virtual machine
+ */
+ static Charset toCharset(final String charsetName) {
+ return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName);
+ }
+
+ /**
+ * Returns the given {@code charset} or the default Charset if {@code charset} is null.
+ *
+ * @param charsetName a Charset or null.
+ * @return the given {@code charset} or the default Charset if {@code charset} is null.
+ */
+ static String toCharsetName(final String charsetName) {
+ return charsetName == null ? Charset.defaultCharset().name() : charsetName;
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java b/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java
new file mode 100644
index 00000000000..9e53fef0866
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/ClassLoaderUtils.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Helps work with {@link ClassLoader}.
+ *
+ * @since 3.10
+ */
+public class ClassLoaderUtils {
+
+ private static final URL[] EMPTY_URL_ARRAY = {};
+
+ /**
+ * Gets the system class loader's URLs, if any.
+ *
+ * @return the system class loader's URLs, if any.
+ * @since 3.13.0
+ */
+ public static URL[] getSystemURLs() {
+ return getURLs(ClassLoader.getSystemClassLoader());
+ }
+
+ /**
+ * Gets the current thread's context class loader's URLs, if any.
+ *
+ * @return the current thread's context class loader's URLs, if any.
+ * @since 3.13.0
+ */
+ public static URL[] getThreadURLs() {
+ return getURLs(Thread.currentThread().getContextClassLoader());
+ }
+
+ private static URL[] getURLs(final ClassLoader cl) {
+ return cl instanceof URLClassLoader ? ((URLClassLoader) cl).getURLs() : EMPTY_URL_ARRAY;
+ }
+
+ /**
+ * Converts the given class loader to a String calling {@link #toString(URLClassLoader)}.
+ *
+ * @param classLoader to URLClassLoader to convert.
+ * @return the formatted string.
+ */
+ public static String toString(final ClassLoader classLoader) {
+ if (classLoader instanceof URLClassLoader) {
+ return toString((URLClassLoader) classLoader);
+ }
+ return Objects.toString(classLoader);
+ }
+
+ /**
+ * Converts the given URLClassLoader to a String in the format {@code "URLClassLoader.toString() + [URL1, URL2, ...]"}.
+ *
+ * @param classLoader to URLClassLoader to convert.
+ * @return the formatted string.
+ */
+ public static String toString(final URLClassLoader classLoader) {
+ return classLoader != null ? classLoader + Arrays.toString(classLoader.getURLs()) : "null";
+ }
+
+ /**
+ * Make private in 4.0.
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public ClassLoaderUtils() {
+ // empty
+ }
+}
diff --git a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
index df3773a344c..db7fbf385db 100644
--- a/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassPathUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,10 +16,14 @@
*/
package org.apache.commons.lang3;
+import java.util.Objects;
+
/**
* Operations regarding the classpath.
*
- *
The methods of this class do not allow {@code null} inputs.
+ *
+ * The methods of this class do not allow {@code null} inputs.
+ *
*
* @since 3.3
*/
@@ -27,104 +31,130 @@
public class ClassPathUtils {
/**
- *
{@code ClassPathUtils} instances should NOT be constructed in
- * standard programming. Instead, the class should be used as
- * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}.
+ * Converts a package name to a Java path ('/').
*
- *
This constructor is public to permit tools that require a JavaBean
- * instance to operate.
+ * @param path the source path.
+ * @return a package name.
+ * @throws NullPointerException if {@code path} is null.
+ * @since 3.13.0
*/
- public ClassPathUtils() {
- super();
+ public static String packageToPath(final String path) {
+ return Objects.requireNonNull(path, "path").replace('.', '/');
+ }
+
+ /**
+ * Converts a Java path ('/') to a package name.
+ *
+ * @param path the source path.
+ * @return a package name.
+ * @throws NullPointerException if {@code path} is null.
+ * @since 3.13.0
+ */
+ public static String pathToPackage(final String path) {
+ return Objects.requireNonNull(path, "path").replace('/', '.');
}
/**
* Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the name.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the name.
+ * @param context The context for constructing the name.
* @param resourceName the resource name to construct the fully qualified name for.
* @return the fully qualified name of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedName(final Class> context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return toFullyQualifiedName(context.getPackage(), resourceName);
}
/**
* Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the name.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the name. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the name.
+ * @param context The context for constructing the name.
* @param resourceName the resource name to construct the fully qualified name for.
* @return the fully qualified name of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedName(final Package context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return context.getName() + "." + resourceName;
}
/**
* Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the path.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the path.
+ * @param context The context for constructing the path.
* @param resourceName the resource name to construct the fully qualified path for.
* @return the fully qualified path of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedPath(final Class> context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
return toFullyQualifiedPath(context.getPackage(), resourceName);
}
-
/**
* Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context.
*
- *
Note that this method does not check whether the resource actually exists.
- * It only constructs the path.
- * Null inputs are not allowed.
+ *
+ * Note that this method does not check whether the resource actually exists. It only constructs the path. Null inputs are not allowed.
+ *
*
- * @param context The context for constructing the path.
+ * @param context The context for constructing the path.
* @param resourceName the resource name to construct the fully qualified path for.
* @return the fully qualified path of the resource with name {@code resourceName}.
- * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null.
+ * @throws NullPointerException if either {@code context} or {@code resourceName} is null.
*/
public static String toFullyQualifiedPath(final Package context, final String resourceName) {
- Validate.notNull(context, "Parameter '%s' must not be null!", "context" );
- Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName");
- return context.getName().replace('.', '/') + "/" + resourceName;
+ Objects.requireNonNull(context, "context");
+ Objects.requireNonNull(resourceName, "resourceName");
+ return packageToPath(context.getName()) + "/" + resourceName;
+ }
+
+ /**
+ * {@link ClassPathUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as
+ * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}.
+ *
+ *
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ *
+ *
+ * @deprecated TODO Make private in 4.0.
+ */
+ @Deprecated
+ public ClassPathUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java
index 0a7480ff8d9..ca9894b794d 100644
--- a/src/main/java/org/apache/commons/lang3/ClassUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,52 +18,91 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
-
-import org.apache.commons.lang3.mutable.MutableObject;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
/**
- *
Operates on classes without using reflection.
+ * Operates on classes without using reflection.
*
- *
This class handles invalid {@code null} inputs as best it can.
- * Each method documents its behaviour in more detail.
+ *
+ * This class handles invalid {@code null} inputs as best it can. Each method documents its behavior in more detail.
+ *
*
- *
The notion of a {@code canonical name} includes the human
- * readable name for the type, for example {@code int[]}. The
- * non-canonical method variants work with the JVM names, such as
- * {@code [I}.
+ *
+ * The notion of a {@code canonical name} includes the human-readable name for the type, for example {@code int[]}. The
+ * non-canonical method variants work with the JVM names, such as {@code [I}.
+ *
*
* @since 2.0
*/
public class ClassUtils {
+
/**
- * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
+ * Enumerates inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
+ *
* @since 3.2
*/
public enum Interfaces {
- INCLUDE, EXCLUDE
+
+ /** Includes interfaces. */
+ INCLUDE,
+
+ /** Excludes interfaces. */
+ EXCLUDE
}
/**
- * The package separator character: '.' == {@value}.
+ * The JLS-specified maximum class name length {@value}.
+ *
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ private static final int MAX_CLASS_NAME_LENGTH = 65535;
+
+ /**
+ * The JVM-specified {@code CONSTANT_Class_info} structure defines an array type descriptor is valid only if it represents {@value} or fewer dimensions.
+ *
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ private static final int MAX_JVM_ARRAY_DIMENSION = 255;
+
+ /**
+ * The maximum number of array dimensions.
+ */
+ private static final int MAX_DIMENSIONS = 255;
+
+ private static final Comparator> COMPARATOR = (o1, o2) -> Objects.compare(getName(o1), getName(o2), String::compareTo);
+
+ /**
+ * The package separator character: {@code '.' == {@value}}.
*/
public static final char PACKAGE_SEPARATOR_CHAR = '.';
/**
- * The package separator String: ".".
+ * The package separator String: {@code "."}.
*/
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
/**
- * The inner class separator character: '$' == {@value}.
+ * The inner class separator character: {@code '$' == {@value}}.
*/
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
@@ -73,342 +112,306 @@ public enum Interfaces {
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
/**
- * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
+ * Maps names of primitives to their corresponding primitive {@link Class}es.
+ */
+ private static final Map> NAME_PRIMITIVE_MAP = new HashMap<>();
+
+ static {
+ NAME_PRIMITIVE_MAP.put(Boolean.TYPE.getName(), Boolean.TYPE);
+ NAME_PRIMITIVE_MAP.put(Byte.TYPE.getName(), Byte.TYPE);
+ NAME_PRIMITIVE_MAP.put(Character.TYPE.getName(), Character.TYPE);
+ NAME_PRIMITIVE_MAP.put(Double.TYPE.getName(), Double.TYPE);
+ NAME_PRIMITIVE_MAP.put(Float.TYPE.getName(), Float.TYPE);
+ NAME_PRIMITIVE_MAP.put(Integer.TYPE.getName(), Integer.TYPE);
+ NAME_PRIMITIVE_MAP.put(Long.TYPE.getName(), Long.TYPE);
+ NAME_PRIMITIVE_MAP.put(Short.TYPE.getName(), Short.TYPE);
+ NAME_PRIMITIVE_MAP.put(Void.TYPE.getName(), Void.TYPE);
+ }
+
+ /**
+ * Maps primitive {@link Class}es to their corresponding wrapper {@link Class}.
*/
- private static final Map, Class>> primitiveWrapperMap = new HashMap, Class>>();
+ private static final Map, Class>> PRIMITIVE_WRAPPER_MAP = new HashMap<>();
+
static {
- primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
- primitiveWrapperMap.put(Byte.TYPE, Byte.class);
- primitiveWrapperMap.put(Character.TYPE, Character.class);
- primitiveWrapperMap.put(Short.TYPE, Short.class);
- primitiveWrapperMap.put(Integer.TYPE, Integer.class);
- primitiveWrapperMap.put(Long.TYPE, Long.class);
- primitiveWrapperMap.put(Double.TYPE, Double.class);
- primitiveWrapperMap.put(Float.TYPE, Float.class);
- primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
+ PRIMITIVE_WRAPPER_MAP.put(Boolean.TYPE, Boolean.class);
+ PRIMITIVE_WRAPPER_MAP.put(Byte.TYPE, Byte.class);
+ PRIMITIVE_WRAPPER_MAP.put(Character.TYPE, Character.class);
+ PRIMITIVE_WRAPPER_MAP.put(Short.TYPE, Short.class);
+ PRIMITIVE_WRAPPER_MAP.put(Integer.TYPE, Integer.class);
+ PRIMITIVE_WRAPPER_MAP.put(Long.TYPE, Long.class);
+ PRIMITIVE_WRAPPER_MAP.put(Double.TYPE, Double.class);
+ PRIMITIVE_WRAPPER_MAP.put(Float.TYPE, Float.class);
+ PRIMITIVE_WRAPPER_MAP.put(Void.TYPE, Void.TYPE);
}
/**
- * Maps wrapper {@code Class}es to their corresponding primitive types.
+ * Maps wrapper {@link Class}es to their corresponding primitive types.
*/
- private static final Map, Class>> wrapperPrimitiveMap = new HashMap, Class>>();
+ private static final Map, Class>> WRAPPER_PRIMITIVE_MAP = new HashMap<>();
+
static {
- for (final Map.Entry, Class>> entry : primitiveWrapperMap.entrySet()) {
- final Class> primitiveClass = entry.getKey();
- final Class> wrapperClass = entry.getValue();
+ PRIMITIVE_WRAPPER_MAP.forEach((primitiveClass, wrapperClass) -> {
if (!primitiveClass.equals(wrapperClass)) {
- wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
+ WRAPPER_PRIMITIVE_MAP.put(wrapperClass, primitiveClass);
}
- }
+ });
}
/**
* Maps a primitive class name to its corresponding abbreviation used in array class names.
*/
- private static final Map abbreviationMap;
+ private static final Map ABBREVIATION_MAP;
/**
* Maps an abbreviation used in array class names to corresponding primitive class name.
*/
- private static final Map reverseAbbreviationMap;
+ private static final Map REVERSE_ABBREVIATION_MAP;
- /**
- * Feed abbreviation maps
- */
+ /** Feed abbreviation maps. */
static {
- final Map m = new HashMap();
- m.put("int", "I");
- m.put("boolean", "Z");
- m.put("float", "F");
- m.put("long", "J");
- m.put("short", "S");
- m.put("byte", "B");
- m.put("double", "D");
- m.put("char", "C");
- m.put("void", "V");
- final Map r = new HashMap();
- for (final Map.Entry e : m.entrySet()) {
- r.put(e.getValue(), e.getKey());
- }
- abbreviationMap = Collections.unmodifiableMap(m);
- reverseAbbreviationMap = Collections.unmodifiableMap(r);
- }
-
- /**
- *
ClassUtils instances should NOT be constructed in standard programming.
- * Instead, the class should be used as
- * {@code ClassUtils.getShortClassName(cls)}.
- *
- *
This constructor is public to permit tools that require a JavaBean
- * instance to operate.
- */
- public ClassUtils() {
- super();
+ final Map map = new HashMap<>();
+ map.put(Integer.TYPE.getName(), "I");
+ map.put(Boolean.TYPE.getName(), "Z");
+ map.put(Float.TYPE.getName(), "F");
+ map.put(Long.TYPE.getName(), "J");
+ map.put(Short.TYPE.getName(), "S");
+ map.put(Byte.TYPE.getName(), "B");
+ map.put(Double.TYPE.getName(), "D");
+ map.put(Character.TYPE.getName(), "C");
+ ABBREVIATION_MAP = Collections.unmodifiableMap(map);
+ REVERSE_ABBREVIATION_MAP = Collections.unmodifiableMap(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)));
}
- // Short class name
- // ----------------------------------------------------------------------
/**
- *
Gets the class name minus the package name for an {@code Object}.
+ * Gets the class comparator, comparing by class name.
*
- * @param object the class to get the short name for, may be null
- * @param valueIfNull the value to return if null
- * @return the class name of the object without the package name, or the null value
+ * @return the class comparator.
+ * @since 3.13.0
*/
- public static String getShortClassName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getShortClassName(object.getClass());
+ public static Comparator> comparator() {
+ return COMPARATOR;
}
/**
- *
Gets the class name minus the package name from a {@code Class}.
+ * Given a {@link List} of {@link Class} objects, this method converts them into class names.
*
- *
Consider using the Java 5 API {@link Class#getSimpleName()} instead.
- * The one known difference is that this code will return {@code "Map.Entry"} while
- * the {@code java.lang.Class} variant will simply return {@code "Entry"}.
+ *
+ * A new {@link List} is returned. {@code null} objects will be copied into the returned list as {@code null}.
+ *
*
- * @param cls the class to get the short name for.
- * @return the class name without the package name or an empty string
+ * @param classes the classes to change.
+ * @return a {@link List} of class names corresponding to the Class objects, {@code null} if null input.
+ * @throws ClassCastException if {@code classes} contains a non-{@link Class} entry.
*/
- public static String getShortClassName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getShortClassName(cls.getName());
+ public static List convertClassesToClassNames(final List> classes) {
+ return classes == null ? null : classes.stream().map(e -> getName(e, null)).collect(Collectors.toList());
}
/**
- *
Gets the class name minus the package name from a String.
+ * Given a {@link List} of class names, this method converts them into classes.
*
- *
The string passed in is assumed to be a class name - it is not checked.
-
- *
Note that this method differs from Class.getSimpleName() in that this will
- * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
- * return {@code "Entry"}.
+ *
+ * A new {@link List} is returned. If the class name cannot be found, {@code null} is stored in the {@link List}. If the
+ * class name in the {@link List} is {@code null}, {@code null} is stored in the output {@link List}.
+ *
*
- * @param className the className to get the short name for
- * @return the class name of the class without the package name or an empty string
+ * @param classNames the classNames to change.
+ * @return a {@link List} of Class objects corresponding to the class names, {@code null} if null input.
+ * @throws ClassCastException if classNames contains a non String entry.
*/
- public static String getShortClassName(String className) {
- if (StringUtils.isEmpty(className)) {
- return StringUtils.EMPTY;
+ public static List> convertClassNamesToClasses(final List classNames) {
+ if (classNames == null) {
+ return null;
}
-
- final StringBuilder arrayPrefix = new StringBuilder();
-
- // Handle array encoding
- if (className.startsWith("[")) {
- while (className.charAt(0) == '[') {
- className = className.substring(1);
- arrayPrefix.append("[]");
- }
- // Strip Object type encoding
- if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
- className = className.substring(1, className.length() - 1);
- }
-
- if (reverseAbbreviationMap.containsKey(className)) {
- className = reverseAbbreviationMap.get(className);
+ final List> classes = new ArrayList<>(classNames.size());
+ classNames.forEach(className -> {
+ try {
+ classes.add(Class.forName(className));
+ } catch (final Exception ex) {
+ classes.add(null);
}
- }
-
- final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
- final int innerIdx = className.indexOf(
- INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
- String out = className.substring(lastDotIdx + 1);
- if (innerIdx != -1) {
- out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
- }
- return out + arrayPrefix;
+ });
+ return classes;
}
/**
- *
Null-safe version of aClass.getSimpleName()
+ * Gets the abbreviated name of a {@link Class}.
*
- * @param cls the class for which to get the simple name.
- * @return the simple class name.
- * @since 3.0
- * @see Class#getSimpleName()
+ * @param cls the class to get the abbreviated name for, may be {@code null}.
+ * @param lengthHint the desired length of the abbreviated name.
+ * @return the abbreviated name or an empty string.
+ * @throws IllegalArgumentException if len <= 0.
+ * @see #getAbbreviatedName(String, int)
+ * @since 3.4
*/
- public static String getSimpleName(final Class> cls) {
+ public static String getAbbreviatedName(final Class> cls, final int lengthHint) {
if (cls == null) {
return StringUtils.EMPTY;
}
- return cls.getSimpleName();
+ return getAbbreviatedName(cls.getName(), lengthHint);
}
/**
- *
Null-safe version of aClass.getSimpleName()
+ * Gets the abbreviated class name from a {@link String}.
*
- * @param object the object for which to get the simple class name.
- * @param valueIfNull the value to return if object is null
- * @return the simple class name.
- * @since 3.0
- * @see Class#getSimpleName()
- */
- public static String getSimpleName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getSimpleName(object.getClass());
- }
-
- // Package name
- // ----------------------------------------------------------------------
- /**
- *
Gets the package name of an {@code Object}.
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
*
- * @param object the class to get the package name for, may be null
- * @param valueIfNull the value to return if null
- * @return the package name of the object, or the null value
- */
- public static String getPackageName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
- }
- return getPackageName(object.getClass());
- }
-
- /**
- *
Gets the package name of a {@code Class}.
+ *
+ * The abbreviation algorithm will shorten the class name, usually without significant loss of meaning.
+ *
*
- * @param cls the class to get the package name for, may be {@code null}.
- * @return the package name or an empty string
- */
- public static String getPackageName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getPackageName(cls.getName());
- }
-
- /**
- *
Gets the package name from a {@code String}.
+ *
+ * The abbreviated class name will always include the complete package hierarchy. If enough space is available,
+ * rightmost sub-packages will be displayed in full length. The abbreviated package names will be shortened to a single
+ * character.
+ *
+ *
+ * Only package names are shortened, the class simple name remains untouched. (See examples.)
+ *
+ *
+ * The result will be longer than the desired length only if all the package names shortened to a single character plus
+ * the class simple name with the separating dots together are longer than the desired length. In other words, when the
+ * class name cannot be shortened to the desired length.
+ *
+ *
+ * If the class name can be shortened then the final length will be at most {@code lengthHint} characters.
+ *
+ *
+ * If the {@code lengthHint} is zero or negative then the method throws exception. If you want to achieve the shortest
+ * possible version then use {@code 1} as a {@code lengthHint}.
+ *
*
- *
The string passed in is assumed to be a class name - it is not checked.
- *
If the class is unpackaged, return an empty string.
+ *
+ *
Examples
+ *
+ *
className
+ *
len
+ *
return
+ *
+ *
+ *
null
+ *
1
+ *
""
+ *
+ *
+ *
"java.lang.String"
+ *
5
+ *
"j.l.String"
+ *
+ *
+ *
"java.lang.String"
+ *
15
+ *
"j.lang.String"
+ *
+ *
+ *
"java.lang.String"
+ *
30
+ *
"java.lang.String"
+ *
+ *
+ *
"org.apache.commons.lang3.ClassUtils"
+ *
18
+ *
"o.a.c.l.ClassUtils"
+ *
+ *
*
- * @param className the className to get the package name for, may be {@code null}
- * @return the package name or an empty string
+ * @param className the className to get the abbreviated name for, may be {@code null}.
+ * @param lengthHint the desired length of the abbreviated name.
+ * @return the abbreviated name or an empty string if the specified class name is {@code null} or empty string. The
+ * abbreviated name may be longer than the desired length if it cannot be abbreviated to the desired length.
+ * @throws IllegalArgumentException if {@code len <= 0}.
+ * @since 3.4
*/
- public static String getPackageName(String className) {
- if (StringUtils.isEmpty(className)) {
- return StringUtils.EMPTY;
+ public static String getAbbreviatedName(final String className, final int lengthHint) {
+ if (lengthHint <= 0) {
+ throw new IllegalArgumentException("len must be > 0");
}
-
- // Strip array encoding
- while (className.charAt(0) == '[') {
- className = className.substring(1);
+ if (className == null) {
+ return StringUtils.EMPTY;
}
- // Strip Object type encoding
- if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
- className = className.substring(1);
+ if (className.length() <= lengthHint) {
+ return className;
}
+ final char[] abbreviated = className.toCharArray();
+ int target = 0;
+ int source = 0;
+ while (source < abbreviated.length) {
+ // copy the next part
+ int runAheadTarget = target;
+ while (source < abbreviated.length && abbreviated[source] != '.') {
+ abbreviated[runAheadTarget++] = abbreviated[source++];
+ }
- final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
- if (i == -1) {
- return StringUtils.EMPTY;
+ ++target;
+ if (useFull(runAheadTarget, source, abbreviated.length, lengthHint) || target > runAheadTarget) {
+ target = runAheadTarget;
+ }
+
+ // copy the '.' unless it was the last part
+ if (source < abbreviated.length) {
+ abbreviated[target++] = abbreviated[source++];
+ }
}
- return className.substring(0, i);
+ return new String(abbreviated, 0, target);
}
- // Abbreviated name
- // ----------------------------------------------------------------------
/**
- *
Gets the abbreviated name of a {@code Class}.
+ * Gets a {@link List} of all interfaces implemented by the given class and its superclasses.
*
- * @param cls the class to get the abbreviated name for, may be {@code null}
- * @param len the desired length of the abbreviated name
- * @return the abbreviated name or an empty string
- * @throws IllegalArgumentException if len <= 0
- * @see #getAbbreviatedName(String, int)
- * @since 3.4
+ *
+ * The order is determined by looking through each interface in turn as declared in the source file and following its
+ * hierarchy up. Then each superclass is considered in the same way. Later duplicates are ignored, so the order is
+ * maintained.
+ *
+ *
+ * @param cls the class to look up, may be {@code null}.
+ * @return the {@link List} of interfaces in order, {@code null} if null input.
*/
- public static String getAbbreviatedName(final Class> cls, int len) {
- if (cls == null) {
- return StringUtils.EMPTY;
- }
- return getAbbreviatedName(cls.getName(), len);
+ public static List> getAllInterfaces(final Class> cls) {
+ if (cls == null) {
+ return null;
+ }
+ final LinkedHashSet> interfacesFound = new LinkedHashSet<>();
+ getAllInterfaces(cls, interfacesFound);
+ return new ArrayList<>(interfacesFound);
}
/**
- *
Gets the abbreviated class name from a {@code String}.
- *
- *
The string passed in is assumed to be a class name - it is not checked.
+ * Gets the interfaces for the specified class.
*
- *
The abbreviation algorithm will shorten the class name, usually without
- * significant loss of meaning.
- *
The abbreviated class name will always include the complete package hierarchy.
- * If enough space is available, rightmost sub-packages will be displayed in full
- * length.
- *
- *
The following table illustrates the algorithm:
- *
- *
className
len
return
- *
null
1
""
- *
"java.lang.String"
5
"j.l.String"
- *
"java.lang.String"
15
"j.lang.String"
- *
"java.lang.String"
30
"java.lang.String"
- *
- * @param className the className to get the abbreviated name for, may be {@code null}
- * @param len the desired length of the abbreviated name
- * @return the abbreviated name or an empty string
- * @throws IllegalArgumentException if len <= 0
- * @since 3.4
+ * @param cls the class to look up, may be {@code null}.
+ * @param interfacesFound the {@link Set} of interfaces for the class.
*/
- public static String getAbbreviatedName(String className, int len) {
- if (len <= 0) {
- throw new IllegalArgumentException("len must be > 0");
- }
- if (className == null) {
- return StringUtils.EMPTY;
- }
-
- int availableSpace = len;
- int packageLevels = StringUtils.countMatches(className, '.');
- String[] output = new String[packageLevels + 1];
- int endIndex = className.length() - 1;
- for (int level = packageLevels; level >= 0; level--) {
- int startIndex = className.lastIndexOf('.', endIndex);
- String part = className.substring(startIndex + 1, endIndex + 1);
- availableSpace -= part.length();
- if (level > 0) {
- // all elements except top level require an additional char space
- availableSpace--;
- }
- if (level == packageLevels) {
- // ClassName is always complete
- output[level] = part;
- } else {
- if (availableSpace > 0) {
- output[level] = part;
- } else {
- // if no space is left still the first char is used
- output[level] = part.substring(0, 1);
- }
+ private static void getAllInterfaces(Class> cls, final Set> interfacesFound) {
+ while (cls != null) {
+ for (final Class> i : cls.getInterfaces()) {
+ if (interfacesFound.add(i)) {
+ getAllInterfaces(i, interfacesFound);
+ }
+ }
+ cls = cls.getSuperclass();
}
- endIndex = startIndex - 1;
- }
-
- return StringUtils.join(output, '.');
}
- // Superclasses/Superinterfaces
- // ----------------------------------------------------------------------
/**
- *
Gets a {@code List} of superclasses for the given class.
+ * Gets a {@link List} of superclasses for the given class.
*
- * @param cls the class to look up, may be {@code null}
- * @return the {@code List} of superclasses in order going up from this one
- * {@code null} if null input
+ *
+ *
The first entry is the superclass of the given class.
+ *
The last entry is {@link Object}'s class.
+ *
+ *
+ * @param cls the class to look up, may be {@code null}.
+ * @return the {@link List} of superclasses in order going up from this one {@code null} if null input.
*/
public static List> getAllSuperclasses(final Class> cls) {
if (cls == null) {
return null;
}
- final List> classes = new ArrayList>();
+ final List> classes = new ArrayList<>();
Class> superclass = cls.getSuperclass();
while (superclass != null) {
classes.add(superclass);
@@ -418,289 +421,917 @@ public static List> getAllSuperclasses(final Class> cls) {
}
/**
- *
Gets a {@code List} of all interfaces implemented by the given
- * class and its superclasses.
+ * Gets the canonical class name for a {@link Class}.
*
- *
The order is determined by looking through each interface in turn as
- * declared in the source file and following its hierarchy up. Then each
- * superclass is considered in the same way. Later duplicates are ignored,
- * so the order is maintained.
+ * @param cls the class for which to get the canonical class name; may be null.
+ * @return the canonical name of the class, or the empty String.
+ * @since 3.7
+ * @see Class#getCanonicalName()
+ */
+ public static String getCanonicalName(final Class> cls) {
+ return getCanonicalName(cls, StringUtils.EMPTY);
+ }
+
+ /**
+ * Gets the canonical name for a {@link Class}.
*
- * @param cls the class to look up, may be {@code null}
- * @return the {@code List} of interfaces in order,
- * {@code null} if null input
+ * @param cls the class for which to get the canonical class name; may be null.
+ * @param valueIfNull the return value if null.
+ * @return the canonical name of the class, or {@code valueIfNull}.
+ * @since 3.7
+ * @see Class#getCanonicalName()
*/
- public static List> getAllInterfaces(final Class> cls) {
+ public static String getCanonicalName(final Class> cls, final String valueIfNull) {
if (cls == null) {
- return null;
+ return valueIfNull;
}
-
- final LinkedHashSet> interfacesFound = new LinkedHashSet>();
- getAllInterfaces(cls, interfacesFound);
-
- return new ArrayList>(interfacesFound);
+ final String canonicalName = cls.getCanonicalName();
+ return canonicalName == null ? valueIfNull : canonicalName;
}
/**
- * Get the interfaces for the specified class.
+ * Gets the canonical name for an {@link Object}.
*
- * @param cls the class to look up, may be {@code null}
- * @param interfacesFound the {@code Set} of interfaces for the class
+ * @param object the object for which to get the canonical class name; may be null.
+ * @return the canonical name of the object, or the empty String.
+ * @since 3.7
+ * @see Class#getCanonicalName()
*/
- private static void getAllInterfaces(Class> cls, final HashSet> interfacesFound) {
- while (cls != null) {
- final Class>[] interfaces = cls.getInterfaces();
-
- for (final Class> i : interfaces) {
- if (interfacesFound.add(i)) {
- getAllInterfaces(i, interfacesFound);
- }
- }
-
- cls = cls.getSuperclass();
- }
- }
+ public static String getCanonicalName(final Object object) {
+ return getCanonicalName(object, StringUtils.EMPTY);
+ }
- // Convert list
- // ----------------------------------------------------------------------
/**
- *
Given a {@code List} of class names, this method converts them into classes.
+ * Gets the canonical name for an {@link Object}.
*
- *
A new {@code List} is returned. If the class name cannot be found, {@code null}
- * is stored in the {@code List}. If the class name in the {@code List} is
- * {@code null}, {@code null} is stored in the output {@code List}.
- *
- * @param classNames the classNames to change
- * @return a {@code List} of Class objects corresponding to the class names,
- * {@code null} if null input
- * @throws ClassCastException if classNames contains a non String entry
+ * @param object the object for which to get the canonical class name; may be null.
+ * @param valueIfNull the return value if null.
+ * @return the canonical name of the object or {@code valueIfNull}.
+ * @since 3.7
+ * @see Class#getCanonicalName()
*/
- public static List> convertClassNamesToClasses(final List classNames) {
- if (classNames == null) {
- return null;
- }
- final List> classes = new ArrayList>(classNames.size());
- for (final String className : classNames) {
- try {
- classes.add(Class.forName(className));
- } catch (final Exception ex) {
- classes.add(null);
- }
+ public static String getCanonicalName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
}
- return classes;
+ final String canonicalName = object.getClass().getCanonicalName();
+ return canonicalName == null ? valueIfNull : canonicalName;
}
/**
- *
Given a {@code List} of {@code Class} objects, this method converts
- * them into class names.
+ * Converts a given name of class into canonical format. If name of class is not a name of array class it returns
+ * unchanged name.
+ *
+ *
+ * The method does not change the {@code $} separators in case the class is inner class.
+ *
*
- *
A new {@code List} is returned. {@code null} objects will be copied into
- * the returned list as {@code null}.
+ *
*
- * @param classes the classes to change
- * @return a {@code List} of class names corresponding to the Class objects,
- * {@code null} if null input
- * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
+ * @param name the name of class.
+ * @return canonical form of class name.
+ * @throws IllegalArgumentException if the class name is invalid.
*/
- public static List convertClassesToClassNames(final List> classes) {
- if (classes == null) {
+ private static String getCanonicalName(final String name) {
+ String className = StringUtils.deleteWhitespace(name);
+ if (className == null) {
return null;
}
- final List classNames = new ArrayList(classes.size());
- for (final Class> cls : classes) {
- if (cls == null) {
- classNames.add(null);
- } else {
- classNames.add(cls.getName());
+ int dim = 0;
+ final int len = className.length();
+ while (dim < len && className.charAt(dim) == '[') {
+ dim++;
+ if (dim > MAX_DIMENSIONS) {
+ throw new IllegalArgumentException(String.format("Maximum array dimension %d exceeded", MAX_DIMENSIONS));
+ }
+ }
+ if (dim >= len) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
+ }
+ if (dim < 1) {
+ return className;
+ }
+ className = className.substring(dim);
+ if (className.startsWith("L")) {
+ if (!className.endsWith(";") || className.length() < 3) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
}
+ className = className.substring(1, className.length() - 1);
+ } else if (className.length() == 1) {
+ final String primitive = REVERSE_ABBREVIATION_MAP.get(className.substring(0, 1));
+ if (primitive == null) {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
+ }
+ className = primitive;
+ } else {
+ throw new IllegalArgumentException(String.format("Invalid class name %s", name));
+ }
+ final StringBuilder canonicalClassNameBuffer = new StringBuilder(className.length() + dim * 2);
+ canonicalClassNameBuffer.append(className);
+ for (int i = 0; i < dim; i++) {
+ canonicalClassNameBuffer.append("[]");
}
- return classNames;
+ return canonicalClassNameBuffer.toString();
}
- // Is assignable
- // ----------------------------------------------------------------------
/**
- *
Checks if an array of Classes can be assigned to another array of Classes.
- *
- *
This method calls {@link #isAssignable(Class, Class) isAssignable} for each
- * Class pair in the input arrays. It can be used to check if a set of arguments
- * (the first parameter) are suitably compatible with a set of method parameter types
- * (the second parameter).
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
- * method takes into account widenings of primitive classes and
- * {@code null}s.
- *
- *
Primitive widenings allow an int to be assigned to a {@code long},
- * {@code float} or {@code double}. This method returns the correct
- * result for these cases.
- *
- *
{@code Null} may be assigned to any reference type. This method will
- * return {@code true} if {@code null} is passed in and the toClass is
- * non-primitive.
- *
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
- *
- *
Since Lang 3.0, this method will default behavior for
- * calculating assignability between primitive and wrapper types corresponding
- * to the running Java version; i.e. autoboxing will be the default
- * behavior in VMs running Java versions > 1.5.
+ * Gets the (initialized) class represented by {@code className} using the {@code classLoader}. This implementation
+ * supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
*
- * @param classArray the array of Classes to check, may be {@code null}
- * @param toClassArray the array of Classes to try to assign into, may be {@code null}
- * @return {@code true} if assignment possible
+ * @param classLoader the class loader to use to load the class.
+ * @param className the class name.
+ * @return the class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static boolean isAssignable(final Class>[] classArray, final Class>... toClassArray) {
- return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
+ public static Class> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
+ return getClass(classLoader, className, true);
}
/**
- *
Checks if an array of Classes can be assigned to another array of Classes.
- *
- *
This method calls {@link #isAssignable(Class, Class) isAssignable} for each
- * Class pair in the input arrays. It can be used to check if a set of arguments
- * (the first parameter) are suitably compatible with a set of method parameter types
- * (the second parameter).
- *
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
- * method takes into account widenings of primitive classes and
- * {@code null}s.
- *
- *
Primitive widenings allow an int to be assigned to a {@code long},
- * {@code float} or {@code double}. This method returns the correct
- * result for these cases.
- *
- *
{@code Null} may be assigned to any reference type. This method will
- * return {@code true} if {@code null} is passed in and the toClass is
- * non-primitive.
- *
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * Gets the class represented by {@code className} using the {@code classLoader}. This implementation supports the
+ * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", and
+ * "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
*
- * @param classArray the array of Classes to check, may be {@code null}
- * @param toClassArray the array of Classes to try to assign into, may be {@code null}
- * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
- * @return {@code true} if assignment possible
+ * @param classLoader the class loader to use to load the class.
+ * @param className the class name.
+ * @param initialize whether the class must be initialized.
+ * @return the class represented by {@code className} using the {@code classLoader}.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static boolean isAssignable(Class>[] classArray, Class>[] toClassArray, final boolean autoboxing) {
- if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
- return false;
- }
- if (classArray == null) {
- classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
- }
- if (toClassArray == null) {
- toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
- }
- for (int i = 0; i < classArray.length; i++) {
- if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) {
- return false;
+ public static Class> getClass(final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
+ // This method was re-written to avoid recursion and stack overflows found by fuzz testing.
+ String next = className;
+ int lastDotIndex = -1;
+ do {
+ try {
+ final Class> clazz = getPrimitiveClass(next);
+ return clazz != null ? clazz : Class.forName(toCleanName(next), initialize, classLoader);
+ } catch (final ClassNotFoundException ex) {
+ lastDotIndex = next.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ if (lastDotIndex != -1) {
+ next = next.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR_CHAR + next.substring(lastDotIndex + 1);
+ }
}
- }
- return true;
+ } while (lastDotIndex != -1);
+ throw new ClassNotFoundException(className);
}
/**
- * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
- * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * Gets the (initialized) class represented by {@code className} using the current thread's context class loader.
+ * This implementation supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
*
- * @param type
- * The class to query or null.
- * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
- * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
- * @since 3.1
+ * @param className the class name
+ * @return the class represented by {@code className} using the current thread's context class loader
+ * @throws NullPointerException if the className is null
+ * @throws ClassNotFoundException if the class is not found
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static boolean isPrimitiveOrWrapper(final Class> type) {
- if (type == null) {
- return false;
+ public static Class> getClass(final String className) throws ClassNotFoundException {
+ return getClass(className, true);
+ }
+
+ /**
+ * Gets the class represented by {@code className} using the current thread's context class loader. This
+ * implementation supports the syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
+ * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
+ *
+ * @param className the class name.
+ * @param initialize whether the class must be initialized.
+ * @return the class represented by {@code className} using the current thread's context class loader.
+ * @throws NullPointerException if the className is null.
+ * @throws ClassNotFoundException if the class is not found.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see Class#forName(String, boolean, ClassLoader)
+ * @see JVM: Array dimension limits in JVM Specification CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
+ */
+ public static Class> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
+ final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
+ return getClass(loader, className, initialize);
+ }
+
+ /**
+ * Delegates to {@link Class#getComponentType()} using generics.
+ *
+ * @param The array class type.
+ * @param cls A class or null.
+ * @return The array component type or null.
+ * @see Class#getComponentType()
+ * @since 3.13.0
+ */
+ @SuppressWarnings("unchecked")
+ public static Class getComponentType(final Class cls) {
+ return cls == null ? null : (Class) cls.getComponentType();
+ }
+
+ /**
+ * Null-safe version of {@code cls.getName()}
+ *
+ * @param cls the class for which to get the class name; may be null.
+ * @return the class name or the empty string in case the argument is {@code null}.
+ * @since 3.7
+ * @see Class#getSimpleName()
+ */
+ public static String getName(final Class> cls) {
+ return getName(cls, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code cls.getName()}
+ *
+ * @param cls the class for which to get the class name; may be null.
+ * @param valueIfNull the return value if the argument {@code cls} is {@code null}.
+ * @return the class name or {@code valueIfNull}
+ * @since 3.7
+ * @see Class#getName()
+ */
+ public static String getName(final Class> cls, final String valueIfNull) {
+ return getName(cls, valueIfNull, false);
+ }
+
+ static String getName(final Class> cls, final String valueIfNull, final boolean simple) {
+ return cls == null ? valueIfNull : simple ? cls.getSimpleName() : cls.getName();
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getName()}
+ *
+ * @param object the object for which to get the class name; may be null.
+ * @return the class name or the empty String.
+ * @since 3.7
+ * @see Class#getSimpleName()
+ */
+ public static String getName(final Object object) {
+ return getName(object, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getSimpleName()}
+ *
+ * @param object the object for which to get the class name; may be null.
+ * @param valueIfNull the value to return if {@code object} is {@code null}.
+ * @return the class name or {@code valueIfNull}.
+ * @since 3.0
+ * @see Class#getName()
+ */
+ public static String getName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : object.getClass().getName();
+ }
+
+ /**
+ * Gets the package name from the canonical name of a {@link Class}.
+ *
+ * @param cls the class to get the package name for, may be {@code null}.
+ * @return the package name or an empty string.
+ * @since 2.4
+ */
+ public static String getPackageCanonicalName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
}
- return type.isPrimitive() || isPrimitiveWrapper(type);
+ return getPackageCanonicalName(cls.getName());
}
/**
- * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
- * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * Gets the package name from the class name of an {@link Object}.
*
- * @param type
- * The class to query or null.
- * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
- * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
- * @since 3.1
+ * @param object the class to get the package name for, may be null.
+ * @param valueIfNull the value to return if null.
+ * @return the package name of the object, or the null value.
+ * @since 2.4
*/
- public static boolean isPrimitiveWrapper(final Class> type) {
- return wrapperPrimitiveMap.containsKey(type);
+ public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getPackageCanonicalName(object.getClass().getName());
}
/**
- *
Checks if one {@code Class} can be assigned to a variable of
- * another {@code Class}.
+ * Gets the package name from the class name.
*
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
- * this method takes into account widenings of primitive classes and
- * {@code null}s.
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
+ *
+ * If the class is in the default package, return an empty string.
+ *
*
- *
Primitive widenings allow an int to be assigned to a long, float or
- * double. This method returns the correct result for these cases.
+ * @param name the name to get the package name for, may be {@code null}.
+ * @return the package name or an empty string.
+ * @since 2.4
+ */
+ public static String getPackageCanonicalName(final String name) {
+ return getPackageName(getCanonicalName(name));
+ }
+
+ /**
+ * Gets the package name of a {@link Class}.
*
- *
{@code Null} may be assigned to any reference type. This method
- * will return {@code true} if {@code null} is passed in and the
- * toClass is non-primitive.
+ * @param cls the class to get the package name for, may be {@code null}.
+ * @return the package name or an empty string
+ */
+ public static String getPackageName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ return getPackageName(cls.getName());
+ }
+
+ /**
+ * Gets the package name of an {@link Object}.
+ *
+ * @param object the class to get the package name for, may be null.
+ * @param valueIfNull the value to return if null.
+ * @return the package name of the object, or the null value.
+ */
+ public static String getPackageName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getPackageName(object.getClass());
+ }
+
+ /**
+ * Gets the package name from a {@link String}.
+ *
+ *
+ * The string passed in is assumed to be a class name.
+ *
+ *
+ * If the class is unpackaged, return an empty string.
+ *
*
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ * @param className the className to get the package name for, may be {@code null}.
+ * @return the package name or an empty string.
+ */
+ public static String getPackageName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ return StringUtils.EMPTY;
+ }
+ int i = 0;
+ // Strip array encoding
+ while (className.charAt(i) == '[') {
+ i++;
+ }
+ className = className.substring(i);
+ // Strip Object type encoding
+ if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
+ className = className.substring(1);
+ }
+ i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ if (i == -1) {
+ return StringUtils.EMPTY;
+ }
+ return className.substring(0, i);
+ }
+
+ /**
+ * Gets the primitive class for the given class name, for example "byte".
+ *
+ * @param className the primitive class for the given class name.
+ * @return the primitive class.
+ */
+ static Class> getPrimitiveClass(final String className) {
+ return NAME_PRIMITIVE_MAP.get(className);
+ }
+
+ /**
+ * Gets the desired Method much like {@code Class.getMethod}, however it ensures that the returned Method is from a
+ * public class or interface and not from an anonymous inner class. This means that the Method is invokable and doesn't
+ * fall foul of Java bug (4071957).
+ *
+ *
+ * {@code Set set = Collections.unmodifiableSet(...);
+ * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
+ * Object result = method.invoke(set, new Object[]);}
+ *
+ *
+ * @param cls the class to check, not null.
+ * @param methodName the name of the method.
+ * @param parameterTypes the list of parameters.
+ * @return the method.
+ * @throws NullPointerException if the class is null.
+ * @throws SecurityException if a security violation occurred.
+ * @throws NoSuchMethodException if the method is not found in the given class or if the method doesn't conform with the
+ * requirements.
+ */
+ public static Method getPublicMethod(final Class> cls, final String methodName, final Class>... parameterTypes) throws NoSuchMethodException {
+ final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
+ if (isPublic(declaredMethod.getDeclaringClass())) {
+ return declaredMethod;
+ }
+ final List> candidateClasses = new ArrayList<>(getAllInterfaces(cls));
+ candidateClasses.addAll(getAllSuperclasses(cls));
+ for (final Class> candidateClass : candidateClasses) {
+ if (!isPublic(candidateClass)) {
+ continue;
+ }
+ final Method candidateMethod;
+ try {
+ candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
+ } catch (final NoSuchMethodException ex) {
+ continue;
+ }
+ if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
+ return candidateMethod;
+ }
+ }
+ throw new NoSuchMethodException("Can't find a public method for " + methodName + " " + ArrayUtils.toString(parameterTypes));
+ }
+
+ /**
+ * Gets the canonical name minus the package name from a {@link Class}.
+ *
+ * @param cls the class for which to get the short canonical class name; may be null.
+ * @return the canonical name without the package name or an empty string.
+ * @since 2.4
+ * @see Class#getCanonicalName()
+ */
+ public static String getShortCanonicalName(final Class> cls) {
+ return cls == null ? StringUtils.EMPTY : getShortCanonicalName(cls.getCanonicalName());
+ }
+
+ /**
+ * Gets the canonical name minus the package name for an {@link Object}.
+ *
+ * @param object the class to get the short name for, may be null.
+ * @param valueIfNull the value to return if null.
+ * @return the canonical name of the object without the package name, or the null value.
+ * @since 2.4
+ * @see Class#getCanonicalName()
+ */
+ public static String getShortCanonicalName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : getShortCanonicalName(object.getClass());
+ }
+
+ /**
+ * Gets the canonical name minus the package name from a String.
*
- *
Since Lang 3.0, this method will default behavior for
- * calculating assignability between primitive and wrapper types corresponding
- * to the running Java version; i.e. autoboxing will be the default
- * behavior in VMs running Java versions > 1.5.
+ *
+ * The string passed in is assumed to be a class name - it is not checked.
+ *
+ *
+ *
+ * Note that this method is mainly designed to handle the arrays and primitives properly. If the class is an inner class
+ * then the result value will not contain the outer classes. This way the behavior of this method is different from
+ * {@link #getShortClassName(String)}. The argument in that case is class name and not canonical name and the return
+ * value retains the outer classes.
+ *
+ *
+ *
+ * Note that there is no way to reliably identify the part of the string representing the package hierarchy and the part
+ * that is the outer class or classes in case of an inner class. Trying to find the class would require reflective call
+ * and the class itself may not even be on the class path. Relying on the fact that class names start with capital
+ * letter and packages with lower case is heuristic.
+ *
+ *
+ *
+ * It is recommended to use {@link #getShortClassName(String)} for cases when the class is an inner class and use this
+ * method for cases it is designed for.
+ *
+ *
+ * @param canonicalName the class name to get the short name for.
+ * @return the canonical name of the class without the package name or an empty string.
+ * @since 2.4
+ */
+ public static String getShortCanonicalName(final String canonicalName) {
+ return getShortClassName(getCanonicalName(canonicalName));
+ }
+
+ /**
+ * Gets the class name minus the package name from a {@link Class}.
+ *
+ * @param cls the class to get the short name for.
+ * @return the class name without the package name or an empty string. If the class is an inner class then the returned
+ * value will contain the outer class or classes separated with {@code .} (dot) character.
+ */
+ public static String getShortClassName(final Class> cls) {
+ if (cls == null) {
+ return StringUtils.EMPTY;
+ }
+ int dim = 0;
+ Class> c = cls;
+ while (c.isArray()) {
+ dim++;
+ c = c.getComponentType();
+ }
+ final String base;
+ // Preserve legacy behavior for anonymous/local classes (keeps compiler ordinals: $13, $10Named, etc.)
+ if (c.isAnonymousClass() || c.isLocalClass()) {
+ base = getShortClassName(c.getName());
+ } else {
+ final Deque parts = new ArrayDeque<>();
+ Class> x = c;
+ while (x != null) {
+ parts.push(x.getSimpleName());
+ x = x.getDeclaringClass();
+ }
+ base = String.join(".", parts);
+ }
+ return base + StringUtils.repeat("[]", dim);
+ }
+
+ /**
+ * Gets the class name of the {@code object} without the package name or names.
+ *
+ * @param object the class to get the short name for, may be {@code null}.
+ * @param valueIfNull the value to return if the object is {@code null}.
+ * @return the class name of the object without the package name, or {@code valueIfNull} if the argument {@code object}
+ * is {@code null}.
+ */
+ public static String getShortClassName(final Object object, final String valueIfNull) {
+ if (object == null) {
+ return valueIfNull;
+ }
+ return getShortClassName(object.getClass());
+ }
+
+ /**
+ * Gets the class name minus the package name from a String.
+ *
+ *
+ * The string passed in is assumed to be a class name - it is not checked. The string has to be formatted the way as the
+ * JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import
+ * statements, or as it is formatted by {@code Class.getCanonicalName()}.
+ *
+ *
+ *
+ * The difference is significant only in case of classes that are inner classes of some other classes. In this case
+ * the separator between the outer and inner class (possibly on multiple hierarchy level) has to be {@code $} (dollar
+ * sign) and not {@code .} (dot), as it is returned by {@code Class.getName()}
+ *
+ *
+ *
+ * Note that this method is called from the {@link #getShortClassName(Class)} method using the string returned by
+ * {@code Class.getName()}.
+ *
+ *
+ *
+ * Note that this method differs from {@link #getSimpleName(Class)} in that this will return, for example
+ * {@code "Map.Entry"} whilst the {@link Class} variant will simply return {@code "Entry"}. In this example
+ * the argument {@code className} is the string {@code java.util.Map$Entry} (note the {@code $} sign).
+ *
+ *
+ * @param className the className to get the short name for. It has to be formatted as returned by
+ * {@code Class.getName()} and not {@code Class.getCanonicalName()}.
+ * @return the class name of the class without the package name or an empty string. If the class is an inner class then
+ * value contains the outer class or classes and the separator is replaced to be {@code .} (dot) character.
+ */
+ public static String getShortClassName(String className) {
+ if (StringUtils.isEmpty(className)) {
+ return StringUtils.EMPTY;
+ }
+ final StringBuilder arrayPrefix = new StringBuilder();
+ // Handle array encoding
+ if (className.startsWith("[")) {
+ while (className.charAt(0) == '[') {
+ className = className.substring(1);
+ arrayPrefix.append("[]");
+ }
+ // Strip Object type encoding
+ if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
+ className = className.substring(1, className.length() - 1);
+ }
+ if (REVERSE_ABBREVIATION_MAP.containsKey(className)) {
+ className = REVERSE_ABBREVIATION_MAP.get(className);
+ }
+ }
+ final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
+ final int innerIdx = className.indexOf(INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
+ String out = className.substring(lastDotIdx + 1);
+ if (innerIdx != -1) {
+ out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
+ }
+ return out + arrayPrefix;
+ }
+
+ /**
+ * Null-safe version of {@code cls.getSimpleName()}
+ *
+ * @param cls the class for which to get the simple name; may be null.
+ * @return the simple class name or the empty string in case the argument is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Class> cls) {
+ return getSimpleName(cls, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code cls.getSimpleName()}
+ *
+ * @param cls the class for which to get the simple name; may be null.
+ * @param valueIfNull the value to return if null.
+ * @return the simple class name or {@code valueIfNull} if the argument {@code cls} is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Class> cls, final String valueIfNull) {
+ return cls == null ? valueIfNull : cls.getSimpleName();
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getSimpleName()}
+ *
+ *
+ * It is to note that this method is overloaded and in case the argument {@code object} is a {@link Class} object then
+ * the {@link #getSimpleName(Class)} will be invoked. If this is a significant possibility then the caller should check
+ * this case and call {@code
+ * getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which is the result of the method
+ * in that case.
+ *
+ *
+ * @param object the object for which to get the simple class name; may be null.
+ * @return the simple class name or the empty string in case the argument is {@code null}.
+ * @since 3.7
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Object object) {
+ return getSimpleName(object, StringUtils.EMPTY);
+ }
+
+ /**
+ * Null-safe version of {@code object.getClass().getSimpleName()}
+ *
+ * @param object the object for which to get the simple class name; may be null.
+ * @param valueIfNull the value to return if {@code object} is {@code null}.
+ * @return the simple class name or {@code valueIfNull} if the argument {@code object} is {@code null}.
+ * @since 3.0
+ * @see Class#getSimpleName()
+ */
+ public static String getSimpleName(final Object object, final String valueIfNull) {
+ return object == null ? valueIfNull : object.getClass().getSimpleName();
+ }
+
+ /**
+ * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
+ * excluding interfaces.
+ *
+ * @param type the type to get the class hierarchy from.
+ * @return Iterable an Iterable over the class hierarchy of the given class.
+ * @since 3.2
+ */
+ public static Iterable> hierarchy(final Class> type) {
+ return hierarchy(type, Interfaces.EXCLUDE);
+ }
+
+ /**
+ * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
+ *
+ * @param type the type to get the class hierarchy from.
+ * @param interfacesBehavior switch indicating whether to include or exclude interfaces.
+ * @return Iterable an Iterable over the class hierarchy of the given class.
+ * @since 3.2
+ */
+ public static Iterable> hierarchy(final Class> type, final Interfaces interfacesBehavior) {
+ final Iterable> classes = () -> {
+ final AtomicReference> next = new AtomicReference<>(type);
+ return new Iterator>() {
+
+ @Override
+ public boolean hasNext() {
+ return next.get() != null;
+ }
+
+ @Override
+ public Class> next() {
+ return next.getAndUpdate(Class::getSuperclass);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ };
+ if (interfacesBehavior != Interfaces.INCLUDE) {
+ return classes;
+ }
+ return () -> {
+ final Set> seenInterfaces = new HashSet<>();
+ final Iterator> wrapped = classes.iterator();
+
+ return new Iterator>() {
+ Iterator> interfaces = Collections.emptyIterator();
+
+ @Override
+ public boolean hasNext() {
+ return interfaces.hasNext() || wrapped.hasNext();
+ }
+
+ @Override
+ public Class> next() {
+ if (interfaces.hasNext()) {
+ final Class> nextInterface = interfaces.next();
+ seenInterfaces.add(nextInterface);
+ return nextInterface;
+ }
+ final Class> nextSuperclass = wrapped.next();
+ final Set> currentInterfaces = new LinkedHashSet<>();
+ walkInterfaces(currentInterfaces, nextSuperclass);
+ interfaces = currentInterfaces.iterator();
+ return nextSuperclass;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private void walkInterfaces(final Set> addTo, final Class> c) {
+ for (final Class> iface : c.getInterfaces()) {
+ if (!seenInterfaces.contains(iface)) {
+ addTo.add(iface);
+ }
+ walkInterfaces(addTo, iface);
+ }
+ }
+
+ };
+ };
+ }
+
+ /**
+ * Tests whether one {@link Class} can be assigned to a variable of another {@link Class}.
+ *
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result
+ * for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ *
+ * Since Lang 3.0, this method will default behavior for calculating assignability between primitive
+ * and wrapper types corresponding to the running Java version; i.e. autoboxing will be the default behavior in
+ * VMs running Java versions > 1.5.
+ *
*
- * @param cls the Class to check, may be null
- * @param toClass the Class to try to assign into, returns false if null
- * @return {@code true} if assignment possible
+ * @param cls the Class to check, may be null.
+ * @param toClass the Class to try to assign into, returns false if null.
+ * @return {@code true} if assignment possible.
*/
public static boolean isAssignable(final Class> cls, final Class> toClass) {
- return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
+ return isAssignable(cls, toClass, true);
}
/**
- *
Checks if one {@code Class} can be assigned to a variable of
- * another {@code Class}.
+ * Tests whether one {@link Class} can be assigned to a variable of another {@link Class}.
*
- *
Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
- * this method takes into account widenings of primitive classes and
- * {@code null}s.
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
*
- *
Primitive widenings allow an int to be assigned to a long, float or
- * double. This method returns the correct result for these cases.
+ *
+ * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result
+ * for these cases.
+ *
*
- *
{@code Null} may be assigned to any reference type. This method
- * will return {@code true} if {@code null} is passed in and the
- * toClass is non-primitive.
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
*
- *
Specifically, this method tests whether the type represented by the
- * specified {@code Class} parameter can be converted to the type
- * represented by this {@code Class} object via an identity conversion
- * widening primitive or widening reference conversion. See
- * The Java Language Specification,
- * sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
*
- * @param cls the Class to check, may be null
- * @param toClass the Class to try to assign into, returns false if null
- * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
- * @return {@code true} if assignment possible
+ * @param cls the Class to check, may be null.
+ * @param toClass the Class to try to assign into, returns false if null.
+ * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers.
+ * @return {@code true} if assignment possible.
*/
public static boolean isAssignable(Class> cls, final Class> toClass, final boolean autoboxing) {
if (toClass == null) {
@@ -710,7 +1341,7 @@ public static boolean isAssignable(Class> cls, final Class> toClass, final b
if (cls == null) {
return !toClass.isPrimitive();
}
- //autoboxing:
+ // autoboxing:
if (autoboxing) {
if (cls.isPrimitive() && !toClass.isPrimitive()) {
cls = primitiveToWrapper(cls);
@@ -729,17 +1360,14 @@ public static boolean isAssignable(Class> cls, final Class> toClass, final b
return true;
}
if (cls.isPrimitive()) {
- if (toClass.isPrimitive() == false) {
+ if (!toClass.isPrimitive()) {
return false;
}
if (Integer.TYPE.equals(cls)) {
- return Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
+ return Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
}
if (Long.TYPE.equals(cls)) {
- return Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
+ return Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
}
if (Boolean.TYPE.equals(cls)) {
return false;
@@ -750,23 +1378,11 @@ public static boolean isAssignable(Class> cls, final Class> toClass, final b
if (Float.TYPE.equals(cls)) {
return Double.TYPE.equals(toClass);
}
- if (Character.TYPE.equals(cls)) {
- return Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
- }
- if (Short.TYPE.equals(cls)) {
- return Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
- || Double.TYPE.equals(toClass);
+ if (Character.TYPE.equals(cls) || Short.TYPE.equals(cls)) {
+ return Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass);
}
if (Byte.TYPE.equals(cls)) {
- return Short.TYPE.equals(toClass)
- || Integer.TYPE.equals(toClass)
- || Long.TYPE.equals(toClass)
- || Float.TYPE.equals(toClass)
+ return Short.TYPE.equals(toClass) || Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
// should never get here
@@ -776,545 +1392,345 @@ public static boolean isAssignable(Class> cls, final Class> toClass, final b
}
/**
- *
Converts the specified primitive Class object to its corresponding
- * wrapper Class object.
+ * Tests whether an array of Classes can be assigned to another array of Classes.
*
- *
NOTE: From v2.2, this method handles {@code Void.TYPE},
- * returning {@code Void.TYPE}.
+ *
+ * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be
+ * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter
+ * types (the second parameter).
+ *
*
- * @param cls the class to convert, may be null
- * @return the wrapper class for {@code cls} or {@code cls} if
- * {@code cls} is not a primitive. {@code null} if null input.
- * @since 2.1
- */
- public static Class> primitiveToWrapper(final Class> cls) {
- Class> convertedClass = cls;
- if (cls != null && cls.isPrimitive()) {
- convertedClass = primitiveWrapperMap.get(cls);
- }
- return convertedClass;
- }
-
- /**
- *
Converts the specified array of primitive Class objects to an array of
- * its corresponding wrapper Class objects.
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
*
- * @param classes the class array to convert, may be null or empty
- * @return an array which contains for each given class, the wrapper class or
- * the original class if class is not a primitive. {@code null} if null input.
- * Empty array if an empty array passed in.
- * @since 2.1
- */
- public static Class>[] primitivesToWrappers(final Class>... classes) {
- if (classes == null) {
- return null;
- }
-
- if (classes.length == 0) {
- return classes;
- }
-
- final Class>[] convertedClasses = new Class[classes.length];
- for (int i = 0; i < classes.length; i++) {
- convertedClasses[i] = primitiveToWrapper(classes[i]);
- }
- return convertedClasses;
- }
-
- /**
- *
Converts the specified wrapper class to its corresponding primitive
- * class.
+ *
+ * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method
+ * returns the correct result for these cases.
+ *
*
- *
This method is the counter part of {@code primitiveToWrapper()}.
- * If the passed in class is a wrapper class for a primitive type, this
- * primitive type will be returned (e.g. {@code Integer.TYPE} for
- * {@code Integer.class}). For other classes, or if the parameter is
- * null, the return value is null.
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
*
- * @param cls the class to convert, may be null
- * @return the corresponding primitive type if {@code cls} is a
- * wrapper class, null otherwise
- * @see #primitiveToWrapper(Class)
- * @since 2.4
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ *
+ * Since Lang 3.0, this method will default behavior for calculating assignability between primitive
+ * and wrapper types corresponding to the running Java version; i.e. autoboxing will be the default behavior in
+ * VMs running Java versions > 1.5.
+ *
+ *
+ * @param classArray the array of Classes to check, may be {@code null}.
+ * @param toClassArray the array of Classes to try to assign into, may be {@code null}.
+ * @return {@code true} if assignment possible.
*/
- public static Class> wrapperToPrimitive(final Class> cls) {
- return wrapperPrimitiveMap.get(cls);
+ public static boolean isAssignable(final Class>[] classArray, final Class>... toClassArray) {
+ return isAssignable(classArray, toClassArray, true);
}
/**
- *
Converts the specified array of wrapper Class objects to an array of
- * its corresponding primitive Class objects.
+ * Tests whether an array of Classes can be assigned to another array of Classes.
*
- *
This method invokes {@code wrapperToPrimitive()} for each element
- * of the passed in array.
+ *
+ * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be
+ * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter
+ * types (the second parameter).
+ *
*
- * @param classes the class array to convert, may be null or empty
- * @return an array which contains for each given class, the primitive class or
- * null if the original class is not a wrapper class. {@code null} if null input.
- * Empty array if an empty array passed in.
- * @see #wrapperToPrimitive(Class)
- * @since 2.4
+ *
+ * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of
+ * primitive classes and {@code null}s.
+ *
+ *
+ *
+ * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method
+ * returns the correct result for these cases.
+ *
+ *
+ *
+ * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in
+ * and the toClass is non-primitive.
+ *
+ *
+ *
+ * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be
+ * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or
+ * widening reference conversion. See The Java Language
+ * Specification, sections 5.1.1, 5.1.2 and 5.1.4 for details.
+ *
+ *
+ * @param classArray the array of Classes to check, may be {@code null}
+ * @param toClassArray the array of Classes to try to assign into, may be {@code null}
+ * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
+ * @return {@code true} if assignment possible
*/
- public static Class>[] wrappersToPrimitives(final Class>... classes) {
- if (classes == null) {
- return null;
- }
-
- if (classes.length == 0) {
- return classes;
+ public static boolean isAssignable(Class>[] classArray, Class>[] toClassArray, final boolean autoboxing) {
+ if (!ArrayUtils.isSameLength(classArray, toClassArray)) {
+ return false;
}
-
- final Class>[] convertedClasses = new Class[classes.length];
- for (int i = 0; i < classes.length; i++) {
- convertedClasses[i] = wrapperToPrimitive(classes[i]);
+ classArray = ArrayUtils.nullToEmpty(classArray);
+ toClassArray = ArrayUtils.nullToEmpty(toClassArray);
+ for (int i = 0; i < classArray.length; i++) {
+ if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) {
+ return false;
+ }
}
- return convertedClasses;
+ return true;
}
- // Inner class
- // ----------------------------------------------------------------------
/**
- *
Is the specified class an inner class or static nested class.
+ * Tests whether the specified class an inner class or static nested class.
*
- * @param cls the class to check, may be null
- * @return {@code true} if the class is an inner or static nested class,
- * false if not or {@code null}
+ * @param cls the class to check, may be null.
+ * @return {@code true} if the class is an inner or static nested class, false if not or {@code null}.
*/
public static boolean isInnerClass(final Class> cls) {
return cls != null && cls.getEnclosingClass() != null;
}
- // Class loading
- // ----------------------------------------------------------------------
- /**
- * Returns the class represented by {@code className} using the
- * {@code classLoader}. This implementation supports the syntaxes
- * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
- * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
- *
- * @param classLoader the class loader to use to load the class
- * @param className the class name
- * @param initialize whether the class must be initialized
- * @return the class represented by {@code className} using the {@code classLoader}
- * @throws ClassNotFoundException if the class is not found
- */
- public static Class> getClass(
- final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
- try {
- Class> clazz;
- if (abbreviationMap.containsKey(className)) {
- final String clsName = "[" + abbreviationMap.get(className);
- clazz = Class.forName(clsName, initialize, classLoader).getComponentType();
- } else {
- clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
- }
- return clazz;
- } catch (final ClassNotFoundException ex) {
- // allow path separators (.) as inner class name separators
- final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
-
- if (lastDotIndex != -1) {
- try {
- return getClass(classLoader, className.substring(0, lastDotIndex) +
- INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
- initialize);
- } catch (final ClassNotFoundException ex2) { // NOPMD
- // ignore exception
- }
- }
-
- throw ex;
- }
- }
-
/**
- * Returns the (initialized) class represented by {@code className}
- * using the {@code classLoader}. This implementation supports
- * the syntaxes "{@code java.util.Map.Entry[]}",
- * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
- * and "{@code [Ljava.util.Map$Entry;}".
+ * Tests whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte},
+ * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
- * @param classLoader the class loader to use to load the class
- * @param className the class name
- * @return the class represented by {@code className} using the {@code classLoader}
- * @throws ClassNotFoundException if the class is not found
+ * @param type The class to query or null.
+ * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte},
+ * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * @since 3.1
*/
- public static Class> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
- return getClass(classLoader, className, true);
+ public static boolean isPrimitiveOrWrapper(final Class> type) {
+ return type != null && type.isPrimitive() || isPrimitiveWrapper(type);
}
/**
- * Returns the (initialized) class represented by {@code className}
- * using the current thread's context class loader. This implementation
- * supports the syntaxes "{@code java.util.Map.Entry[]}",
- * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
- * and "{@code [Ljava.util.Map$Entry;}".
+ * Tests whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
+ * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
- * @param className the class name
- * @return the class represented by {@code className} using the current thread's context class loader
- * @throws ClassNotFoundException if the class is not found
+ * @param type The class to query or null.
+ * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
+ * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
+ * @since 3.1
*/
- public static Class> getClass(final String className) throws ClassNotFoundException {
- return getClass(className, true);
+ public static boolean isPrimitiveWrapper(final Class> type) {
+ return WRAPPER_PRIMITIVE_MAP.containsKey(type);
}
/**
- * Returns the class represented by {@code className} using the
- * current thread's context class loader. This implementation supports the
- * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
- * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
+ * Tests whether a {@link Class} is public.
*
- * @param className the class name
- * @param initialize whether the class must be initialized
- * @return the class represented by {@code className} using the current thread's context class loader
- * @throws ClassNotFoundException if the class is not found
+ * @param cls Class to test.
+ * @return {@code true} if {@code cls} is public.
+ * @since 3.13.0
*/
- public static Class> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
- final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
- final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
- return getClass(loader, className, initialize);
+ public static boolean isPublic(final Class> cls) {
+ return Modifier.isPublic(cls.getModifiers());
}
- // Public method
- // ----------------------------------------------------------------------
/**
- *
Returns the desired Method much like {@code Class.getMethod}, however
- * it ensures that the returned Method is from a public class or interface and not
- * from an anonymous inner class. This means that the Method is invokable and
- * doesn't fall foul of Java bug
- * 4071957).
+ * Converts the specified array of primitive Class objects to an array of its corresponding wrapper Class objects.
*
- *
- * Set set = Collections.unmodifiableSet(...);
- * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
- * Object result = method.invoke(set, new Object[]);
- *
- *
- * @param cls the class to check, not null
- * @param methodName the name of the method
- * @param parameterTypes the list of parameters
- * @return the method
- * @throws NullPointerException if the class is null
- * @throws SecurityException if a security violation occurred
- * @throws NoSuchMethodException if the method is not found in the given class
- * or if the method doesn't conform with the requirements
+ * @param classes the class array to convert, may be null or empty.
+ * @return an array which contains for each given class, the wrapper class or the original class if class is not a primitive. {@code null} if null input.
+ * Empty array if an empty array passed in.
+ * @since 2.1
*/
- public static Method getPublicMethod(final Class> cls, final String methodName, final Class>... parameterTypes)
- throws SecurityException, NoSuchMethodException {
-
- final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
- if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
- return declaredMethod;
+ public static Class>[] primitivesToWrappers(final Class>... classes) {
+ if (classes == null) {
+ return null;
}
-
- final List> candidateClasses = new ArrayList>();
- candidateClasses.addAll(getAllInterfaces(cls));
- candidateClasses.addAll(getAllSuperclasses(cls));
-
- for (final Class> candidateClass : candidateClasses) {
- if (!Modifier.isPublic(candidateClass.getModifiers())) {
- continue;
- }
- Method candidateMethod;
- try {
- candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
- } catch (final NoSuchMethodException ex) {
- continue;
- }
- if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
- return candidateMethod;
- }
+ if (classes.length == 0) {
+ return classes;
}
-
- throw new NoSuchMethodException("Can't find a public method for " +
- methodName + " " + ArrayUtils.toString(parameterTypes));
+ return ArrayUtils.setAll(new Class[classes.length], i -> primitiveToWrapper(classes[i]));
}
- // ----------------------------------------------------------------------
/**
- * Converts a class name to a JLS style class name.
+ * Converts the specified primitive Class object to its corresponding wrapper Class object.
+ *
+ *
+ * NOTE: From v2.2, this method handles {@code Void.TYPE}, returning {@code Void.TYPE}.
+ *
*
- * @param className the class name
- * @return the converted name
+ * @param cls the class to convert, may be null.
+ * @return the wrapper class for {@code cls} or {@code cls} if {@code cls} is not a primitive. {@code null} if null input.
+ * @since 2.1
*/
- private static String toCanonicalName(String className) {
- className = StringUtils.deleteWhitespace(className);
- if (className == null) {
- throw new NullPointerException("className must not be null.");
- } else if (className.endsWith("[]")) {
- final StringBuilder classNameBuffer = new StringBuilder();
- while (className.endsWith("[]")) {
- className = className.substring(0, className.length() - 2);
- classNameBuffer.append("[");
- }
- final String abbreviation = abbreviationMap.get(className);
- if (abbreviation != null) {
- classNameBuffer.append(abbreviation);
- } else {
- classNameBuffer.append("L").append(className).append(";");
- }
- className = classNameBuffer.toString();
- }
- return className;
+ public static Class> primitiveToWrapper(final Class> cls) {
+ return cls != null && cls.isPrimitive() ? PRIMITIVE_WRAPPER_MAP.get(cls) : cls;
}
/**
- *
Converts an array of {@code Object} in to an array of {@code Class} objects.
- * If any of these objects is null, a null element will be inserted into the array.
+ * Converts an array of {@link Object} in to an array of {@link Class} objects. If any of these objects is null, a null element will be inserted into the
+ * array.
*
- *
This method returns {@code null} for a {@code null} input array.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
*
- * @param array an {@code Object} array
- * @return a {@code Class} array, {@code null} if null array input
+ * @param array an {@link Object} array.
+ * @return a {@link Class} array, {@code null} if null array input.
* @since 2.4
*/
public static Class>[] toClass(final Object... array) {
if (array == null) {
return null;
- } else if (array.length == 0) {
- return ArrayUtils.EMPTY_CLASS_ARRAY;
}
- final Class>[] classes = new Class[array.length];
- for (int i = 0; i < array.length; i++) {
- classes[i] = array[i] == null ? null : array[i].getClass();
+ if (array.length == 0) {
+ return ArrayUtils.EMPTY_CLASS_ARRAY;
}
- return classes;
+ return ArrayUtils.setAll(new Class[array.length], i -> array[i] == null ? null : array[i].getClass());
}
- // Short canonical name
- // ----------------------------------------------------------------------
/**
- *
Gets the canonical name minus the package name for an {@code Object}.
+ * Converts and cleans up a class name to a JLS style class name.
+ *
+ * The provided class name is normalized by removing all whitespace. This is especially helpful when handling XML element values in which whitespace has not
+ * been collapsed.
+ *
*
- * @param object the class to get the short name for, may be null
- * @param valueIfNull the value to return if null
- * @return the canonical name of the object without the package name, or the null value
- * @since 2.4
+ * @param className the class name.
+ * @return the converted name.
+ * @throws NullPointerException if the className is null.
+ * @throws IllegalArgumentException Thrown if the class name represents an array with more dimensions than the JVM supports, 255.
+ * @throws IllegalArgumentException Thrown if the class name length is greater than 65,535.
+ * @see JVM: Array dimension limits in JVM Specification
+ * CONSTANT_Class_info
+ * @see JLS: Fully Qualified Names and Canonical Names
+ * @see JLS: The Form of a Binary
*/
- public static String getShortCanonicalName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
+ private static String toCleanName(final String className) {
+ String canonicalName = StringUtils.deleteWhitespace(className);
+ Objects.requireNonNull(canonicalName, "className");
+ if (canonicalName.isEmpty()) {
+ throw new IllegalArgumentException("Class name is empty");
}
- return getShortCanonicalName(object.getClass().getName());
- }
-
- /**
- *
Gets the canonical name minus the package name from a {@code Class}.
- *
- * @param cls the class to get the short name for.
- * @return the canonical name without the package name or an empty string
- * @since 2.4
- */
- public static String getShortCanonicalName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
+ final String encodedArrayOpen = "[";
+ final String encodedClassNameStart = "L";
+ final String encodedClassNameEnd = ";";
+ final boolean encodedName = canonicalName.startsWith(encodedArrayOpen) && canonicalName.endsWith(encodedClassNameEnd);
+ if (encodedName) {
+ final int arrIdx = canonicalName.indexOf(encodedClassNameStart);
+ if (arrIdx > MAX_JVM_ARRAY_DIMENSION) {
+ throw new IllegalArgumentException("Array dimension greater than JVM specification maximum of 255.");
+ }
+ if (arrIdx < 0) {
+ throw new IllegalArgumentException("Expected 'L' after '[' for an array style string.");
+ }
+ final int cnLen = canonicalName.length() - (arrIdx + 2); // account for the ending ';'
+ if (cnLen > MAX_CLASS_NAME_LENGTH) {
+ throw new IllegalArgumentException(String.format("Class name greater than maxium length %,d", MAX_CLASS_NAME_LENGTH));
+ }
}
- return getShortCanonicalName(cls.getName());
- }
-
- /**
- *
Gets the canonical name minus the package name from a String.
- *
- *
The string passed in is assumed to be a canonical name - it is not checked.
- *
- * @param canonicalName the class name to get the short name for
- * @return the canonical name of the class without the package name or an empty string
- * @since 2.4
- */
- public static String getShortCanonicalName(final String canonicalName) {
- return ClassUtils.getShortClassName(getCanonicalName(canonicalName));
- }
-
- // Package name
- // ----------------------------------------------------------------------
- /**
- *
Gets the package name from the canonical name of an {@code Object}.
- *
- * @param object the class to get the package name for, may be null
- * @param valueIfNull the value to return if null
- * @return the package name of the object, or the null value
- * @since 2.4
- */
- public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
- if (object == null) {
- return valueIfNull;
+ final String arrayMarker = "[]";
+ final int arrIdx = canonicalName.indexOf(arrayMarker);
+ // The class name length without array markers.
+ final int cnLen = arrIdx > 0 ? arrIdx : canonicalName.length();
+ if (cnLen > MAX_CLASS_NAME_LENGTH && !encodedName) {
+ throw new IllegalArgumentException(String.format("Class name greater than maxium length %,d", MAX_CLASS_NAME_LENGTH));
}
- return getPackageCanonicalName(object.getClass().getName());
- }
-
- /**
- *
Gets the package name from the canonical name of a {@code Class}.
- *
- * @param cls the class to get the package name for, may be {@code null}.
- * @return the package name or an empty string
- * @since 2.4
- */
- public static String getPackageCanonicalName(final Class> cls) {
- if (cls == null) {
- return StringUtils.EMPTY;
+ if (canonicalName.endsWith(arrayMarker)) {
+ final int dims = (canonicalName.length() - arrIdx) / 2;
+ if (dims > MAX_JVM_ARRAY_DIMENSION) {
+ throw new IllegalArgumentException("Array dimension greater than JVM specification maximum of 255.");
+ }
+ final StringBuilder classNameBuffer = new StringBuilder(StringUtils.repeat(encodedArrayOpen, dims));
+ canonicalName = canonicalName.substring(0, arrIdx);
+ final String abbreviation = ABBREVIATION_MAP.get(canonicalName);
+ if (abbreviation != null) {
+ classNameBuffer.append(abbreviation);
+ } else {
+ classNameBuffer.append(encodedClassNameStart).append(canonicalName).append(encodedClassNameEnd);
+ }
+ canonicalName = classNameBuffer.toString();
}
- return getPackageCanonicalName(cls.getName());
+ return canonicalName;
}
/**
- *
Gets the package name from the canonical name.
- *
- *
The string passed in is assumed to be a canonical name - it is not checked.
- *
If the class is unpackaged, return an empty string.
+ * Decides if the part that was just copied to its destination location in the work array can be kept as it was copied
+ * or must be abbreviated. It must be kept when the part is the last one, which is the simple name of the class. In this
+ * case the {@code source} index, from where the characters are copied points one position after the last character,
+ * a.k.a. {@code source ==
+ * originalLength}
+ *
+ *
+ * If the part is not the last one then it can be kept unabridged if the number of the characters copied so far plus the
+ * character that are to be copied is less than or equal to the desired length.
+ *
*
- * @param canonicalName the canonical name to get the package name for, may be {@code null}
- * @return the package name or an empty string
- * @since 2.4
+ * @param runAheadTarget the target index (where the characters were copied to) pointing after the last character copied
+ * when the current part was copied.
+ * @param source the source index (where the characters were copied from) pointing after the last character copied when
+ * the current part was copied.
+ * @param originalLength the original length of the class full name, which is abbreviated.
+ * @param desiredLength the desired length of the abbreviated class name.
+ * @return {@code true} if it can be kept in its original length; {@code false} if the current part has to be abbreviated.
*/
- public static String getPackageCanonicalName(final String canonicalName) {
- return ClassUtils.getPackageName(getCanonicalName(canonicalName));
+ private static boolean useFull(final int runAheadTarget, final int source, final int originalLength, final int desiredLength) {
+ return source >= originalLength || runAheadTarget + originalLength - source <= desiredLength;
}
/**
- *
Converts a given name of class into canonical format.
- * If name of class is not a name of array class it returns
- * unchanged name.
+ * Converts the specified array of wrapper Class objects to an array of its corresponding primitive Class objects.
+ *
+ *
+ * This method invokes {@code wrapperToPrimitive()} for each element of the passed in array.
*
*
- * @param className the name of class
- * @return canonical form of class name
+ * @param classes the class array to convert, may be null or empty.
+ * @return an array which contains for each given class, the primitive class or {@code null} if the original class is not a wrapper class.
+ * {@code null} if null input. Empty array if an empty array passed in.
+ * @see #wrapperToPrimitive(Class)
* @since 2.4
*/
- private static String getCanonicalName(String className) {
- className = StringUtils.deleteWhitespace(className);
- if (className == null) {
+ public static Class>[] wrappersToPrimitives(final Class>... classes) {
+ if (classes == null) {
return null;
}
- int dim = 0;
- while (className.startsWith("[")) {
- dim++;
- className = className.substring(1);
- }
- if (dim < 1) {
- return className;
- }
- if (className.startsWith("L")) {
- className = className.substring(
- 1,
- className.endsWith(";")
- ? className.length() - 1
- : className.length());
- } else {
- if (className.length() > 0) {
- className = reverseAbbreviationMap.get(className.substring(0, 1));
- }
- }
- final StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
- for (int i = 0; i < dim; i++) {
- canonicalClassNameBuffer.append("[]");
+ if (classes.length == 0) {
+ return classes;
}
- return canonicalClassNameBuffer.toString();
+ return ArrayUtils.setAll(new Class[classes.length], i -> wrapperToPrimitive(classes[i]));
}
/**
- * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
- * excluding interfaces.
+ * Converts the specified wrapper class to its corresponding primitive class.
*
- * @param type the type to get the class hierarchy from
- * @return Iterable an Iterable over the class hierarchy of the given class
- * @since 3.2
+ *
+ * This method is the counter part of {@code primitiveToWrapper()}. If the passed in class is a wrapper class for a
+ * primitive type, this primitive type will be returned (e.g. {@code Integer.TYPE} for {@code Integer.class}). For other
+ * classes, or if the parameter is {@code null}, the return value is {@code null}.
+ *
+ *
+ * @param cls the class to convert, may be {@code null}.
+ * @return the corresponding primitive type if {@code cls} is a wrapper class, {@code null} otherwise.
+ * @see #primitiveToWrapper(Class)
+ * @since 2.4
*/
- public static Iterable> hierarchy(final Class> type) {
- return hierarchy(type, Interfaces.EXCLUDE);
+ public static Class> wrapperToPrimitive(final Class> cls) {
+ return WRAPPER_PRIMITIVE_MAP.get(cls);
}
/**
- * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
+ * ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
+ * {@code ClassUtils.getShortClassName(cls)}.
*
- * @param type the type to get the class hierarchy from
- * @param interfacesBehavior switch indicating whether to include or exclude interfaces
- * @return Iterable an Iterable over the class hierarchy of the given class
- * @since 3.2
+ *
+ * This constructor is public to permit tools that require a JavaBean instance to operate.
+ *
+ *
+ * @deprecated TODO Make private in 4.0.
*/
- public static Iterable> hierarchy(final Class> type, final Interfaces interfacesBehavior) {
- final Iterable> classes = new Iterable>() {
-
- @Override
- public Iterator> iterator() {
- final MutableObject> next = new MutableObject>(type);
- return new Iterator>() {
-
- @Override
- public boolean hasNext() {
- return next.getValue() != null;
- }
-
- @Override
- public Class> next() {
- final Class> result = next.getValue();
- next.setValue(result.getSuperclass());
- return result;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- }
-
- };
- if (interfacesBehavior != Interfaces.INCLUDE) {
- return classes;
- }
- return new Iterable>() {
-
- @Override
- public Iterator> iterator() {
- final Set> seenInterfaces = new HashSet>();
- final Iterator> wrapped = classes.iterator();
-
- return new Iterator>() {
- Iterator> interfaces = Collections.> emptySet().iterator();
-
- @Override
- public boolean hasNext() {
- return interfaces.hasNext() || wrapped.hasNext();
- }
-
- @Override
- public Class> next() {
- if (interfaces.hasNext()) {
- final Class> nextInterface = interfaces.next();
- seenInterfaces.add(nextInterface);
- return nextInterface;
- }
- final Class> nextSuperclass = wrapped.next();
- final Set> currentInterfaces = new LinkedHashSet>();
- walkInterfaces(currentInterfaces, nextSuperclass);
- interfaces = currentInterfaces.iterator();
- return nextSuperclass;
- }
-
- private void walkInterfaces(final Set> addTo, final Class> c) {
- for (final Class> iface : c.getInterfaces()) {
- if (!seenInterfaces.contains(iface)) {
- addTo.add(iface);
- }
- walkInterfaces(addTo, iface);
- }
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- };
- }
- };
+ @Deprecated
+ public ClassUtils() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/Conversion.java b/src/main/java/org/apache/commons/lang3/Conversion.java
index 05df5943038..2b858a05997 100644
--- a/src/main/java/org/apache/commons/lang3/Conversion.java
+++ b/src/main/java/org/apache/commons/lang3/Conversion.java
@@ -1,34 +1,33 @@
-/*******************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *******************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.apache.commons.lang3;
import java.util.UUID;
-
/**
- *
* Static methods to convert a type into another, with endianness and bit ordering awareness.
- *
+ *
*
- * The methods names follow a naming rule:
- * {@code [source endianness][source bit ordering]To[destination endianness][destination bit ordering]}
+ * The methods names follow a naming rule:
*
+ *
{@code
+ * [source endianness][source bit ordering]To[destination endianness][destination bit ordering]
+ * }
*
* Source/destination type fields is one of the following:
*
@@ -38,294 +37,189 @@
*
int or intArray
*
long or longArray
*
hex: a String containing hexadecimal digits (lowercase in destination)
- *
hexDigit: a Char containing a hexadecimal digit (lowercase in destination)
+ *
hexDigit: a {@code char} containing a hexadecimal digit (lowercase in destination)
*
uuid
*
*
- * Endianness field: little endian is the default, in this case the field is absent. In case of
- * big endian, the field is "Be". Bit ordering: Lsb0 is the default, in this case the field
- * is absent. In case of Msb0, the field is "Msb0".
+ * Endianness field: little-endian is the default, in this case the field is absent. In case of big-endian, the field is "Be".
+ *
+ *
+ * Bit ordering: LSB0 is the default, in this case the field is absent. In case of MSB0, the field is "Msb0" (Camel-case).
*
*
- * Example: intBeMsb0ToHex convert an int with big endian byte order and Msb0 bit order into its
- * hexadecimal string representation
+ * Example: intBeMsb0ToHex convert an {@code int} with big-endian byte order and MSB0 bit order into its hexadecimal string representation
*
*
- * Most of the methods provide only default encoding for destination, this limits the number of
- * ways to do one thing. Unless you are dealing with data from/to outside of the JVM platform,
- * you should not need to use "Be" and "Msb0" methods.
+ * Most of the methods provide only default encoding for destination, this limits the number of ways to do one thing. Unless you are dealing with data from/to
+ * outside of the JVM platform, you should not need to use "Be" and "Msb0" methods.
*
*
- * Development status: work on going, only a part of the little endian, Lsb0 methods implemented
- * so far.
+ * Development status: work on going, only a part of the little-endian, LSB0 methods implemented so far.
*
- *
- * @since Lang 3.2
+ *
+ * @since 3.2
*/
-
public class Conversion {
-
- private static final boolean[] TTTT = new boolean[] { true, true, true, true };
- private static final boolean[] FTTT = new boolean[] { false, true, true, true };
- private static final boolean[] TFTT = new boolean[] { true, false, true, true };
- private static final boolean[] FFTT = new boolean[] { false, false, true, true };
- private static final boolean[] TTFT = new boolean[] { true, true, false, true };
- private static final boolean[] FTFT = new boolean[] { false, true, false, true };
- private static final boolean[] TFFT = new boolean[] { true, false, false, true };
- private static final boolean[] FFFT = new boolean[] { false, false, false, true };
- private static final boolean[] TTTF = new boolean[] { true, true, true, false };
- private static final boolean[] FTTF = new boolean[] { false, true, true, false };
- private static final boolean[] TFTF = new boolean[] { true, false, true, false };
- private static final boolean[] FFTF = new boolean[] { false, false, true, false };
- private static final boolean[] TTFF = new boolean[] { true, true, false, false };
- private static final boolean[] FTFF = new boolean[] { false, true, false, false };
- private static final boolean[] TFFF = new boolean[] { true, false, false, false };
- private static final boolean[] FFFF = new boolean[] { false, false, false, false };
- /**
- *
- * Converts a hexadecimal digit into an int using the default (Lsb0) bit ordering.
- *
- *
- * '1' is converted to 1
- *
- *
- * @param hexDigit the hexadecimal digit to convert
- * @return an int equals to {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
- */
- public static int hexDigitToInt(final char hexDigit) {
- final int digit = Character.digit(hexDigit, 16);
- if (digit < 0) {
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
- }
- return digit;
- }
+ private static final boolean[] TTTT = { true, true, true, true };
+ private static final boolean[] FTTT = { false, true, true, true };
+ private static final boolean[] TFTT = { true, false, true, true };
+ private static final boolean[] FFTT = { false, false, true, true };
+ private static final boolean[] TTFT = { true, true, false, true };
+ private static final boolean[] FTFT = { false, true, false, true };
+ private static final boolean[] TFFT = { true, false, false, true };
+ private static final boolean[] FFFT = { false, false, false, true };
+ private static final boolean[] TTTF = { true, true, true, false };
+ private static final boolean[] FTTF = { false, true, true, false };
+ private static final boolean[] TFTF = { true, false, true, false };
+ private static final boolean[] FFTF = { false, false, true, false };
+ private static final boolean[] TTFF = { true, true, false, false };
+ private static final boolean[] FTFF = { false, true, false, false };
+ private static final boolean[] TFFF = { true, false, false, false };
+ private static final boolean[] FFFF = { false, false, false, false };
/**
+ * Converts the first 4 bits of a binary (represented as boolean array) in big-endian MSB0 bit ordering to a hexadecimal digit.
+ *
*
- * Converts a hexadecimal digit into an int using the Msb0 bit ordering.
- *
- *
- * '1' is converted to 8
+ * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0) is converted to '4'.
*
- *
- * @param hexDigit the hexadecimal digit to convert
- * @return an int equals to {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ *
+ * @param src the binary to convert.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
- public static int hexDigitMsb0ToInt(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return 0x0;
- case '1':
- return 0x8;
- case '2':
- return 0x4;
- case '3':
- return 0xC;
- case '4':
- return 0x2;
- case '5':
- return 0xA;
- case '6':
- return 0x6;
- case '7':
- return 0xE;
- case '8':
- return 0x1;
- case '9':
- return 0x9;
- case 'a':// fall through
- case 'A':
- return 0x5;
- case 'b':// fall through
- case 'B':
- return 0xD;
- case 'c':// fall through
- case 'C':
- return 0x3;
- case 'd':// fall through
- case 'D':
- return 0xB;
- case 'e':// fall through
- case 'E':
- return 0x7;
- case 'f':// fall through
- case 'F':
- return 0xF;
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
- }
+ public static char binaryBeMsb0ToHexDigit(final boolean[] src) {
+ return binaryBeMsb0ToHexDigit(src, 0);
}
/**
+ * Converts a binary (represented as boolean array) in big-endian MSB0 bit ordering to a hexadecimal digit.
+ *
*
- * Converts a hexadecimal digit into binary (represented as boolean array) using the default
- * (Lsb0) bit ordering.
- *
- *
- * '1' is converted as follow: (1, 0, 0, 0)
+ * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0) with srcPos = 2 is converted to '5'.
*
- *
- * @param hexDigit the hexadecimal digit to convert
- * @return a boolean array with the binary representation of {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position of the LSB to start the conversion.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code srcPos} is outside the array.
*/
- public static boolean[] hexDigitToBinary(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return FFFF.clone();
- case '1':
- return TFFF.clone();
- case '2':
- return FTFF.clone();
- case '3':
- return TTFF.clone();
- case '4':
- return FFTF.clone();
- case '5':
- return TFTF.clone();
- case '6':
- return FTTF.clone();
- case '7':
- return TTTF.clone();
- case '8':
- return FFFT.clone();
- case '9':
- return TFFT.clone();
- case 'a':// fall through
- case 'A':
- return FTFT.clone();
- case 'b':// fall through
- case 'B':
- return TTFT.clone();
- case 'c':// fall through
- case 'C':
- return FFTT.clone();
- case 'd':// fall through
- case 'D':
- return TFTT.clone();
- case 'e':// fall through
- case 'E':
- return FTTT.clone();
- case 'f':// fall through
- case 'F':
- return TTTT.clone();
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
+ public static char binaryBeMsb0ToHexDigit(final boolean[] src, final int srcPos) {
+ // JDK 9: Objects.checkIndex(int index, int length)
+ if (Integer.compareUnsigned(srcPos, src.length) >= 0) {
+ // Throw the correct exception
+ if (src.length == 0) {
+ throw new IllegalArgumentException("Cannot convert an empty array.");
+ }
+ throw new IndexOutOfBoundsException(srcPos + " is not within array length " + src.length);
+ }
+ // Little-endian bit 0 position
+ final int pos = src.length - 1 - srcPos;
+ if (3 <= pos && src[pos - 3]) {
+ if (src[pos - 2]) {
+ if (src[pos - 1]) {
+ return src[pos] ? 'f' : 'e';
+ }
+ return src[pos] ? 'd' : 'c';
+ }
+ if (src[pos - 1]) {
+ return src[pos] ? 'b' : 'a';
+ }
+ return src[pos] ? '9' : '8';
+ }
+ if (2 <= pos && src[pos - 2]) {
+ if (src[pos - 1]) {
+ return src[pos] ? '7' : '6';
+ }
+ return src[pos] ? '5' : '4';
}
+ if (1 <= pos && src[pos - 1]) {
+ return src[pos] ? '3' : '2';
+ }
+ return src[pos] ? '1' : '0';
}
/**
- *
- * Converts a hexadecimal digit into binary (represented as boolean array) using the Msb0
- * bit ordering.
- *
- *
- * '1' is converted as follow: (0, 0, 0, 1)
- *
- *
- * @param hexDigit the hexadecimal digit to convert
- * @return a boolean array with the binary representation of {@code hexDigit}
- * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit
+ * Converts binary (represented as boolean array) into a byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination byte.
+ * @param dstPos the position of the LSB, in bits, in the result byte.
+ * @param nBools the number of booleans to convert.
+ * @return a byte containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 8}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static boolean[] hexDigitMsb0ToBinary(final char hexDigit) {
- switch (hexDigit) {
- case '0':
- return FFFF.clone();
- case '1':
- return FFFT.clone();
- case '2':
- return FFTF.clone();
- case '3':
- return FFTT.clone();
- case '4':
- return FTFF.clone();
- case '5':
- return FTFT.clone();
- case '6':
- return FTTF.clone();
- case '7':
- return FTTT.clone();
- case '8':
- return TFFF.clone();
- case '9':
- return TFFT.clone();
- case 'a':// fall through
- case 'A':
- return TFTF.clone();
- case 'b':// fall through
- case 'B':
- return TFTT.clone();
- case 'c':// fall through
- case 'C':
- return TTFF.clone();
- case 'd':// fall through
- case 'D':
- return TTFT.clone();
- case 'e':// fall through
- case 'E':
- return TTTF.clone();
- case 'f':// fall through
- case 'F':
- return TTTT.clone();
- default:
- throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit");
+ public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
+ }
+ if (nBools - 1 + dstPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 8");
+ }
+ byte out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = (byte) (out & ~mask | bits);
}
+ return out;
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the default (LSB0) bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the default
- * (Lsb0) bit ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '1'
+ * (1, 0, 0, 0) is converted as follow: '1'.
*
- *
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ *
+ * @param src the binary to convert.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigit(final boolean[] src) {
return binaryToHexDigit(src, 0);
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the default (LSB0) bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the default
- * (Lsb0) bit ordering.
+ * (1, 0, 0, 0) is converted as follow: '1'.
*
- *
- * (1, 0, 0, 0) is converted as follow: '1'
- *
- *
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position of the LSB to start the conversion.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigit(final boolean[] src, final int srcPos) {
if (src.length == 0) {
throw new IllegalArgumentException("Cannot convert an empty array.");
}
if (src.length > srcPos + 3 && src[srcPos + 3]) {
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
+ if (src[srcPos + 2]) {
+ if (src[srcPos + 1]) {
return src[srcPos] ? 'f' : 'e';
}
return src[srcPos] ? 'd' : 'c';
}
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
+ if (src[srcPos + 1]) {
return src[srcPos] ? 'b' : 'a';
}
return src[srcPos] ? '9' : '8';
}
if (src.length > srcPos + 2 && src[srcPos + 2]) {
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
+ if (src[srcPos + 1]) {
return src[srcPos] ? '7' : '6';
}
return src[srcPos] ? '5' : '4';
@@ -337,47 +231,40 @@ public static char binaryToHexDigit(final boolean[] src, final int srcPos) {
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the MSB0 bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
- * ordering.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '8'
+ * (1, 0, 0, 0) is converted as follow: '8'.
*
- *
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or
- * {@code src.length > 8}
- * @throws NullPointerException if {@code src} is {@code null}
+ *
+ * @param src the binary to convert.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or {@code src.length > 8}.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigitMsb0_4bits(final boolean[] src) {
return binaryToHexDigitMsb0_4bits(src, 0);
}
/**
+ * Converts binary (represented as boolean array) to a hexadecimal digit using the MSB0 bit ordering.
+ *
*
- * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit
- * ordering.
+ * (1, 0, 0, 0) is converted as follow: '8' (1, 0, 0, 1, 1, 0, 1, 0) with srcPos = 3 is converted to 'D'
*
- *
- * (1, 0, 0, 0) is converted as follow: '8' (1,0,0,1,1,0,1,0) with srcPos = 3 is converted
- * to 'D'
- *
- *
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or
- * {@code src.length - srcPos < 4}
- * @throws NullPointerException if {@code src} is {@code null}
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position of the LSB to start the conversion.
+ * @return a hexadecimal digit representing the selected bits.
+ * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or {@code src.length - srcPos < 4}.
+ * @throws NullPointerException if {@code src} is {@code null}.
*/
public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int srcPos) {
- if (src.length > 8) {
- throw new IllegalArgumentException("src.length>8: src.length=" + src.length);
+ if (src.length > Byte.SIZE) {
+ throw new IllegalArgumentException("src.length > 8: src.length=" + src.length);
}
if (src.length - srcPos < 4) {
- throw new IllegalArgumentException("src.length-srcPos<4: src.length=" + src.length + ", srcPos=" + srcPos);
+ throw new IllegalArgumentException("src.length - srcPos < 4: src.length=" + src.length + ", srcPos=" + srcPos);
}
if (src[srcPos + 3]) {
if (src[srcPos + 2]) {
@@ -404,859 +291,865 @@ public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int src
}
/**
- *
- * Converts the first 4 bits of a binary (represented as boolean array) in big endian Msb0
- * bit ordering to a hexadecimal digit.
- *
- *
- * (1, 0, 0, 0) is converted as follow: '8' (1,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,0) is converted
- * to '4'
- *
- *
- * @param src the binary to convert
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * Converts binary (represented as boolean array) into an int using the default (little endian, LSB0) byte and bit ordering.
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos the position of the LSB, in bits, in the result int.
+ * @param nBools the number of booleans to convert.
+ * @return an int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char binaryBeMsb0ToHexDigit(final boolean[] src) {
- return binaryBeMsb0ToHexDigit(src, 0);
+ public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
+ }
+ if (nBools - 1 + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 32");
+ }
+ int out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = out & ~mask | bits;
+ }
+ return out;
}
/**
- *
- * Converts a binary (represented as boolean array) in big endian Msb0 bit ordering to a
- * hexadecimal digit.
- *
- *
- * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1,0,0,0,0,0,0,0,
- * 0,0,0,1,0,1,0,0) with srcPos = 2 is converted to '5'
- *
- *
- * @param src the binary to convert
- * @param srcPos the position of the lsb to start the conversion
- * @return a hexadecimal digit representing the selected bits
- * @throws IllegalArgumentException if {@code src} is empty
- * @throws NullPointerException if {@code src} is {@code null}
+ * Converts binary (represented as boolean array) into a long using the default (little endian, LSB0) byte and bit ordering.
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos the position of the LSB, in bits, in the result long.
+ * @param nBools the number of booleans to convert.
+ * @return a long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char binaryBeMsb0ToHexDigit(boolean[] src, int srcPos) {
- if (src.length == 0) {
- throw new IllegalArgumentException("Cannot convert an empty array.");
- }
- final int beSrcPos = src.length - 1 - srcPos;
- final int srcLen = Math.min(4, beSrcPos + 1);
- final boolean[] paddedSrc = new boolean[4];
- System.arraycopy(src, beSrcPos + 1 - srcLen, paddedSrc, 4 - srcLen, srcLen);
- src = paddedSrc;
- srcPos = 0;
- if (src[srcPos]) {
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'f' : 'e';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'd' : 'c';
- }
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? 'b' : 'a';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? '9' : '8';
+ public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
}
- if (src.length > srcPos + 1 && src[srcPos + 1]) {
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? '7' : '6';
- }
- return src.length > srcPos + 3 && src[srcPos + 3] ? '5' : '4';
+ if (nBools - 1 + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 64");
}
- if (src.length > srcPos + 2 && src[srcPos + 2]) {
- return src.length > srcPos + 3 && src[srcPos + 3] ? '3' : '2';
+ long out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final long bits = (src[i + srcPos] ? 1L : 0) << shift;
+ final long mask = 0x1L << shift;
+ out = out & ~mask | bits;
}
- return src.length > srcPos + 3 && src[srcPos + 3] ? '1' : '0';
+ return out;
}
/**
- *
- * Converts the 4 lsb of an int to a hexadecimal digit.
- *
- *
- * 0 returns '0'
- *
- *
- * 1 returns '1'
- *
- *
- * 10 returns 'A' and so on...
- *
- *
- * @param nibble the 4 bits to convert
- * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
- * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
+ * Converts binary (represented as boolean array) into a short using the default (little endian, LSB0) byte and bit ordering.
+ *
+ * @param src the binary to convert.
+ * @param srcPos the position in {@code src}, in boolean unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos the position of the LSB, in bits, in the result short.
+ * @param nBools the number of booleans to convert.
+ * @return a short containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + dstPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}.
*/
- public static char intToHexDigit(final int nibble) {
- final char c = Character.forDigit(nibble, 16);
- if (c == Character.MIN_VALUE) {
- throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos, final int nBools) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ return dstInit;
}
- return c;
+ if (nBools - 1 + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + dstPos >= 16");
+ }
+ short out = dstInit;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + dstPos;
+ final int bits = (src[i + srcPos] ? 1 : 0) << shift;
+ final int mask = 0x1 << shift;
+ out = (short) (out & ~mask | bits);
+ }
+ return out;
}
/**
- *
- * Converts the 4 lsb of an int to a hexadecimal digit encoded using the Msb0 bit ordering.
- *
- *
- * 0 returns '0'
- *
- *
- * 1 returns '8'
- *
- *
- * 10 returns '5' and so on...
- *
- *
- * @param nibble the 4 bits to convert
- * @return a hexadecimal digit representing the 4 lsb of {@code nibble}
- * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}
+ * Converts an array of byte into an int using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte array to convert.
+ * @param srcPos the position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos the position of the LSB, in bits, in the result int.
+ * @param nBytes the number of bytes to convert.
+ * @return an int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static char intToHexDigitMsb0(final int nibble) {
- switch (nibble) {
- case 0x0:
- return '0';
- case 0x1:
- return '8';
- case 0x2:
- return '4';
- case 0x3:
- return 'c';
- case 0x4:
- return '2';
- case 0x5:
- return 'a';
- case 0x6:
- return '6';
- case 0x7:
- return 'e';
- case 0x8:
- return '1';
- case 0x9:
- return '9';
- case 0xA:
- return '5';
- case 0xB:
- return 'd';
- case 0xC:
- return '3';
- case 0xD:
- return 'b';
- case 0xE:
- return '7';
- case 0xF:
- return 'f';
- default:
- throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
+ return dstInit;
+ }
+ if ((nBytes - 1) * Byte.SIZE + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 32");
}
+ int out = dstInit;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final int bits = (0xff & src[i + srcPos]) << shift;
+ final int mask = 0xff << shift;
+ out = out & ~mask | bits;
+ }
+ return out;
}
/**
- *
- * Converts an array of int into a long using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the int array to convert
- * @param srcPos the position in {@code src}, in int unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nInts the number of ints to convert
- * @return a long containing the selected bits
- * @throws IllegalArgumentException if {@code (nInts-1)*32+dstPos >= 64}
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length}
+ * Converts an array of byte into a long using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte array to convert.
+ * @param srcPos the position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos the position of the LSB, in bits, in the result long.
+ * @param nBytes the number of bytes to convert.
+ * @return a long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nInts) {
- if (src.length == 0 && srcPos == 0 || 0 == nInts) {
+ public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
return dstInit;
}
- if ((nInts - 1) * 32 + dstPos >= 64) {
- throw new IllegalArgumentException("(nInts-1)*32+dstPos is greather or equal to than 64");
+ if ((nBytes - 1) * Byte.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 64");
}
long out = dstInit;
- for (int i = 0; i < nInts; i++) {
- final int shift = i * 32 + dstPos;
- final long bits = (0xffffffffL & src[i + srcPos]) << shift;
- final long mask = 0xffffffffL << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final long bits = (0xffL & src[i + srcPos]) << shift;
+ final long mask = 0xffL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts an array of short into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the short array to convert
- * @param srcPos the position in {@code src}, in short unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nShorts the number of shorts to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
+ * Converts an array of byte into a short using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte array to convert.
+ * @param srcPos the position in {@code src}, in byte unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos the position of the LSB, in bits, in the result short.
+ * @param nBytes the number of bytes to convert.
+ * @return a short containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + dstPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}.
*/
- public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nShorts) {
- if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
+ public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos, final int nBytes) {
+ if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
return dstInit;
}
- if ((nShorts - 1) * 16 + dstPos >= 64) {
- throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greather or equal to than 64");
+ if ((nBytes - 1) * Byte.SIZE + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 16");
}
- long out = dstInit;
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + dstPos;
- final long bits = (0xffffL & src[i + srcPos]) << shift;
- final long mask = 0xffffL << shift;
- out = (out & ~mask) | bits;
+ short out = dstInit;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + dstPos;
+ final int bits = (0xff & src[i + srcPos]) << shift;
+ final int mask = 0xff << shift;
+ out = (short) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts an array of short into a int using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the short array to convert
- * @param srcPos the position in {@code src}, in short unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nShorts the number of shorts to convert
- * @return a int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}
+ * Converts bytes from an array into a UUID using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte array to convert.
+ * @param srcPos the position in {@code src} where to copy the result from.
+ * @return a UUID.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning with {@code srcPos}.
*/
- public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nShorts) {
- if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
- return dstInit;
- }
- if ((nShorts - 1) * 16 + dstPos >= 32) {
- throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greather or equal to than 32");
- }
- int out = dstInit;
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + dstPos;
- final int bits = (0xffff & src[i + srcPos]) << shift;
- final int mask = 0xffff << shift;
- out = (out & ~mask) | bits;
+ public static UUID byteArrayToUuid(final byte[] src, final int srcPos) {
+ if (src.length - srcPos < 16) {
+ throw new IllegalArgumentException("Need at least 16 bytes for UUID");
}
- return out;
+ return new UUID(byteArrayToLong(src, srcPos, 0, 0, Byte.SIZE), byteArrayToLong(src, srcPos + 8, 0, 0, Byte.SIZE));
}
/**
- *
- * Converts an array of byte into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nBytes the number of bytes to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ * Converts a byte into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 8}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
- return dstInit;
+ public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
+ return dst;
}
- if ((nBytes - 1) * 8 + dstPos >= 64) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greather or equal to than 64");
+ if (nBools - 1 + srcPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 8");
}
- long out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final long bits = (0xffL & src[i + srcPos]) << shift;
- final long mask = 0xffL << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
- return out;
+ return dst;
}
/**
- *
- * Converts an array of byte into a int using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nBytes the number of bytes to convert
- * @return a int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ * Converts a byte into an array of char using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the byte to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit the initial value for the result String.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nHexs the number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 8}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
+ public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
return dstInit;
}
- if ((nBytes - 1) * 8 + dstPos >= 32) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greather or equal to than 32");
+ if ((nHexs - 1) * 4 + srcPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 8");
}
- int out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final int bits = (0xff & src[i + srcPos]) << shift;
- final int mask = 0xff << shift;
- out = (out & ~mask) | bits;
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return out;
+ return sb.toString();
}
/**
+ * Converts a hexadecimal digit into binary (represented as boolean array) using the MSB0 bit ordering.
+ *
*
- * Converts an array of byte into a short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted as follow: (0, 0, 0, 1).
*
- *
- * @param src the byte array to convert
- * @param srcPos the position in {@code src}, in byte unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nBytes the number of bytes to convert
- * @return a short containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length}
+ *
+ * @param hexChar the hexadecimal digit to convert.
+ * @return a boolean array with the binary representation of {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos,
- final int nBytes) {
- if (src.length == 0 && srcPos == 0 || 0 == nBytes) {
- return dstInit;
- }
- if ((nBytes - 1) * 8 + dstPos >= 16) {
- throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greather or equal to than 16");
- }
- short out = dstInit;
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + dstPos;
- final int bits = (0xff & src[i + srcPos]) << shift;
- final int mask = 0xff << shift;
- out = (short) ((out & ~mask) | bits);
+ public static boolean[] hexDigitMsb0ToBinary(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return FFFF.clone();
+ case '1':
+ return FFFT.clone();
+ case '2':
+ return FFTF.clone();
+ case '3':
+ return FFTT.clone();
+ case '4':
+ return FTFF.clone();
+ case '5':
+ return FTFT.clone();
+ case '6':
+ return FTTF.clone();
+ case '7':
+ return FTTT.clone();
+ case '8':
+ return TFFF.clone();
+ case '9':
+ return TFFT.clone();
+ case 'a':// fall through
+ case 'A':
+ return TFTF.clone();
+ case 'b':// fall through
+ case 'B':
+ return TFTT.clone();
+ case 'c':// fall through
+ case 'C':
+ return TTFF.clone();
+ case 'd':// fall through
+ case 'D':
+ return TTFT.clone();
+ case 'e':// fall through
+ case 'E':
+ return TTTF.clone();
+ case 'f':// fall through
+ case 'F':
+ return TTTT.clone();
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into an int using the MSB0 bit ordering.
+ *
*
- * Converts an array of Char into a long using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted to 8.
*
- *
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nHex the number of Chars to convert
- * @return a long containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 64}
+ *
+ * @param hexChar the hexadecimal digit to convert.
+ * @return an int equals to {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos,
- final int nHex) {
- if (0 == nHex) {
- return dstInit;
- }
- if ((nHex - 1) * 4 + dstPos >= 64) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greather or equal to than 64");
- }
- long out = dstInit;
- for (int i = 0; i < nHex; i++) {
- final int shift = i * 4 + dstPos;
- final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift;
- final long mask = 0xfL << shift;
- out = (out & ~mask) | bits;
+ public static int hexDigitMsb0ToInt(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return 0x0;
+ case '1':
+ return 0x8;
+ case '2':
+ return 0x4;
+ case '3':
+ return 0xC;
+ case '4':
+ return 0x2;
+ case '5':
+ return 0xA;
+ case '6':
+ return 0x6;
+ case '7':
+ return 0xE;
+ case '8':
+ return 0x1;
+ case '9':
+ return 0x9;
+ case 'a':// fall through
+ case 'A':
+ return 0x5;
+ case 'b':// fall through
+ case 'B':
+ return 0xD;
+ case 'c':// fall through
+ case 'C':
+ return 0x3;
+ case 'd':// fall through
+ case 'D':
+ return 0xB;
+ case 'e':// fall through
+ case 'E':
+ return 0x7;
+ case 'f':// fall through
+ case 'F':
+ return 0xF;
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into binary (represented as boolean array) using the default (LSB0) bit ordering.
+ *
*
- * Converts an array of Char into a int using the default (little endian, Lsb0) byte and bit
- * ordering.
+ * '1' is converted as follow: (1, 0, 0, 0).
*
- *
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nHex the number of Chars to convert
- * @return a int containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 32}
+ *
+ * @param hexChar the hexadecimal digit to convert.
+ * @return a boolean array with the binary representation of {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) {
- if (0 == nHex) {
- return dstInit;
- }
- if ((nHex - 1) * 4 + dstPos >= 32) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greather or equal to than 32");
- }
- int out = dstInit;
- for (int i = 0; i < nHex; i++) {
- final int shift = i * 4 + dstPos;
- final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
- final int mask = 0xf << shift;
- out = (out & ~mask) | bits;
+ public static boolean[] hexDigitToBinary(final char hexChar) {
+ switch (hexChar) {
+ case '0':
+ return FFFF.clone();
+ case '1':
+ return TFFF.clone();
+ case '2':
+ return FTFF.clone();
+ case '3':
+ return TTFF.clone();
+ case '4':
+ return FFTF.clone();
+ case '5':
+ return TFTF.clone();
+ case '6':
+ return FTTF.clone();
+ case '7':
+ return TTTF.clone();
+ case '8':
+ return FFFT.clone();
+ case '9':
+ return TFFT.clone();
+ case 'a':// fall through
+ case 'A':
+ return FTFT.clone();
+ case 'b':// fall through
+ case 'B':
+ return TTFT.clone();
+ case 'c':// fall through
+ case 'C':
+ return FFTT.clone();
+ case 'd':// fall through
+ case 'D':
+ return TFTT.clone();
+ case 'e':// fall through
+ case 'E':
+ return FTTT.clone();
+ case 'f':// fall through
+ case 'F':
+ return TTTT.clone();
+ default:
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
}
- return out;
}
/**
+ * Converts a hexadecimal digit into an int using the default (LSB0) bit ordering.
+ *
*
- * Converts an array of Char into a short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * '1' is converted to 1
*
- *
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nHex the number of Chars to convert
- * @return a short containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 16}
+ *
+ * @param hexChar the hexadecimal digit to convert.
+ * @return an int equals to {@code hexDigit}.
+ * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit.
*/
- public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos,
- final int nHex) {
+ public static int hexDigitToInt(final char hexChar) {
+ final int digit = Character.digit(hexChar, 16);
+ if (digit < 0) {
+ throw new IllegalArgumentException("Cannot convert '" + hexChar + "' to a hexadecimal digit");
+ }
+ return digit;
+ }
+
+ /**
+ * Converts a hexadecimal string into a byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the hexadecimal string to convert.
+ * @param srcPos the position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination byte.
+ * @param dstPos the position of the LSB, in bits, in the result byte.
+ * @param nHex the number of Chars to convert.
+ * @return a byte containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHex-1)*4+dstPos >= 8}.
+ */
+ public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos, final int nHex) {
if (0 == nHex) {
return dstInit;
}
- if ((nHex - 1) * 4 + dstPos >= 16) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greather or equal to than 16");
+ if ((nHex - 1) * 4 + dstPos >= Byte.SIZE) {
+ throw new IllegalArgumentException("(nHex - 1) * 4 + dstPos >= 8");
}
- short out = dstInit;
+ byte out = dstInit;
for (int i = 0; i < nHex; i++) {
final int shift = i * 4 + dstPos;
final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
final int mask = 0xf << shift;
- out = (short) ((out & ~mask) | bits);
+ out = (byte) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts an array of Char into a byte using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the hex string to convert
- * @param srcPos the position in {@code src}, in Char unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination byte
- * @param dstPos the position of the lsb, in bits, in the result byte
- * @param nHex the number of Chars to convert
- * @return a byte containing the selected bits
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 8}
+ * Converts an array of char into an int using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the hexadecimal string to convert.
+ * @param srcPos the position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos the position of the LSB, in bits, in the result int.
+ * @param nHex the number of chars to convert.
+ * @return an int containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 32}.
*/
- public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos,
- final int nHex) {
+ public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) {
if (0 == nHex) {
return dstInit;
}
- if ((nHex - 1) * 4 + dstPos >= 8) {
- throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greather or equal to than 8");
+ if ((nHex - 1) * 4 + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 32");
}
- byte out = dstInit;
+ int out = dstInit;
for (int i = 0; i < nHex; i++) {
final int shift = i * 4 + dstPos;
final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
final int mask = 0xf << shift;
- out = (byte) ((out & ~mask) | bits);
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a long using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
- *
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination long
- * @param dstPos the position of the lsb, in bits, in the result long
- * @param nBools the number of booleans to convert
- * @return a long containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * Converts an array of char into a long using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the hexadecimal string to convert.
+ * @param srcPos the position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos the position of the LSB, in bits, in the result long.
+ * @param nHex the number of chars to convert.
+ * @return a long containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 64}.
*/
- public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos, final int nHex) {
+ if (0 == nHex) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 64) {
- throw new IllegalArgumentException("nBools-1+dstPos is greather or equal to than 64");
+ if ((nHex - 1) * 4 + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 64");
}
long out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final long bits = (src[i + srcPos] ? 1L : 0) << shift;
- final long mask = 0x1L << shift;
- out = (out & ~mask) | bits;
+ for (int i = 0; i < nHex; i++) {
+ final int shift = i * 4 + dstPos;
+ final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift;
+ final long mask = 0xfL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a int using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
- *
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination int
- * @param dstPos the position of the lsb, in bits, in the result int
- * @param nBools the number of booleans to convert
- * @return a int containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * Converts an array of char into a short using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the hexadecimal string to convert.
+ * @param srcPos the position in {@code src}, in char unit, from where to start the conversion.
+ * @param dstInit initial value of the destination short.
+ * @param dstPos the position of the LSB, in bits, in the result short.
+ * @param nHex the number of chars to convert.
+ * @return a short containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + dstPos >= 16}.
*/
- public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos, final int nHex) {
+ if (0 == nHex) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 32) {
- throw new IllegalArgumentException("nBools-1+dstPos is greather or equal to than 32");
+ if ((nHex - 1) * 4 + dstPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 16");
}
- int out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (out & ~mask) | bits;
+ short out = dstInit;
+ for (int i = 0; i < nHex; i++) {
+ final int shift = i * 4 + dstPos;
+ final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift;
+ final int mask = 0xf << shift;
+ out = (short) (out & ~mask | bits);
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a short using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
- *
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination short
- * @param dstPos the position of the lsb, in bits, in the result short
- * @param nBools the number of booleans to convert
- * @return a short containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * Converts an array of int into a long using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the int array to convert.
+ * @param srcPos the position in {@code src}, in int unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos the position of the LSB, in bits, in the result long.
+ * @param nInts the number of ints to convert.
+ * @return a long containing the selected bits.
+ * @throws IllegalArgumentException if {@code (nInts - 1) * 32 + dstPos >= 64}.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length}.
*/
- public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
+ public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos, final int nInts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nInts) {
return dstInit;
}
- if (nBools - 1 + dstPos >= 16) {
- throw new IllegalArgumentException("nBools-1+dstPos is greather or equal to than 16");
+ if ((nInts - 1) * Integer.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nInts - 1) * 32 + dstPos >= 64");
}
- short out = dstInit;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (short) ((out & ~mask) | bits);
+ long out = dstInit;
+ for (int i = 0; i < nInts; i++) {
+ final int shift = i * Integer.SIZE + dstPos;
+ final long bits = (0xffffffffL & src[i + srcPos]) << shift;
+ final long mask = 0xffffffffL << shift;
+ out = out & ~mask | bits;
}
return out;
}
/**
- *
- * Converts binary (represented as boolean array) into a byte using the default (little
- * endian, Lsb0) byte and bit ordering.
- *
- *
- * @param src the binary to convert
- * @param srcPos the position in {@code src}, in boolean unit, from where to start the
- * conversion
- * @param dstInit initial value of the destination byte
- * @param dstPos the position of the lsb, in bits, in the result byte
- * @param nBools the number of booleans to convert
- * @return a byte containing the selected bits
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 8}
- * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length}
+ * Converts an int into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the int to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos,
- final int nBools) {
- if (src.length == 0 && srcPos == 0 || 0 == nBools) {
- return dstInit;
+ public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
+ return dst;
}
- if (nBools - 1 + dstPos >= 8) {
- throw new IllegalArgumentException("nBools-1+dstPos is greather or equal to than 8");
+ if (nBools - 1 + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 32");
}
- byte out = dstInit;
for (int i = 0; i < nBools; i++) {
- final int shift = i + dstPos;
- final int bits = (src[i + srcPos] ? 1 : 0) << shift;
- final int mask = 0x1 << shift;
- out = (byte) ((out & ~mask) | bits);
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
- return out;
+ return dst;
}
/**
- *
- * Converts a long into an array of int using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nInts the number of ints to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0}
- * @throws IllegalArgumentException if {@code (nInts-1)*32+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length}
+ * Converts an int into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the int to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos,
- final int nInts) {
- if (0 == nInts) {
+ public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
+ if (0 == nBytes) {
return dst;
}
- if ((nInts - 1) * 32 + srcPos >= 64) {
- throw new IllegalArgumentException("(nInts-1)*32+srcPos is greather or equal to than 64");
+ if ((nBytes - 1) * Byte.SIZE + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 32");
}
- for (int i = 0; i < nInts; i++) {
- final int shift = i * 32 + srcPos;
- dst[dstPos + i] = (int) (0xffffffff & (src >> shift));
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a long into an array of short using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
+ * Converts an int into an array of char using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the int to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit the initial value for the result String.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nHexs the number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 32}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos,
- final int nShorts) {
- if (0 == nShorts) {
- return dst;
+ public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
+ return dstInit;
}
- if ((nShorts - 1) * 16 + srcPos >= 64) {
- throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greather or equal to than 64");
+ if ((nHexs - 1) * 4 + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 32");
}
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + srcPos;
- dst[dstPos + i] = (short) (0xffff & (src >> shift));
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return dst;
+ return sb.toString();
}
/**
+ * Converts the 4 LSB of an int to a hexadecimal digit.
+ *
+ *
+ * 0 returns '0'
+ *
+ *
+ * 1 returns '1'
+ *
*
- * Converts a int into an array of short using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * 10 returns 'A' and so on...
*
- *
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}
+ *
+ * @param nibble the 4 bits to convert.
+ * @return a hexadecimal digit representing the 4 LSB of {@code nibble}.
+ * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}.
*/
- public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos,
- final int nShorts) {
- if (0 == nShorts) {
- return dst;
- }
- if ((nShorts - 1) * 16 + srcPos >= 32) {
- throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greather or equal to than 32");
- }
- for (int i = 0; i < nShorts; i++) {
- final int shift = i * 16 + srcPos;
- dst[dstPos + i] = (short) (0xffff & (src >> shift));
+ public static char intToHexDigit(final int nibble) {
+ final char c = Character.forDigit(nibble, 16);
+ if (c == Character.MIN_VALUE) {
+ throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
}
- return dst;
+ return c;
}
/**
+ * Converts the 4 LSB of an int to a hexadecimal digit encoded using the MSB0 bit ordering.
+ *
+ *
+ * 0 returns '0'
+ *
+ *
+ * 1 returns '8'
+ *
*
- * Converts a long into an array of byte using the default (little endian, Lsb0) byte and
- * bit ordering.
+ * 10 returns '5' and so on...
*
- *
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ *
+ * @param nibble the 4 bits to convert.
+ * @return a hexadecimal digit representing the 4 LSB of {@code nibble}.
+ * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15}.
*/
- public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
- if (0 == nBytes) {
+ public static char intToHexDigitMsb0(final int nibble) {
+ switch (nibble) {
+ case 0x0:
+ return '0';
+ case 0x1:
+ return '8';
+ case 0x2:
+ return '4';
+ case 0x3:
+ return 'c';
+ case 0x4:
+ return '2';
+ case 0x5:
+ return 'a';
+ case 0x6:
+ return '6';
+ case 0x7:
+ return 'e';
+ case 0x8:
+ return '1';
+ case 0x9:
+ return '9';
+ case 0xA:
+ return '5';
+ case 0xB:
+ return 'd';
+ case 0xC:
+ return '3';
+ case 0xD:
+ return 'b';
+ case 0xE:
+ return '7';
+ case 0xF:
+ return 'f';
+ default:
+ throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble);
+ }
+ }
+
+ /**
+ * Converts an int into an array of short using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the int to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + srcPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}.
+ */
+ public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos, final int nShorts) {
+ if (0 == nShorts) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 64) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greather or equal to than 64");
+ if ((nShorts - 1) * Short.SIZE + srcPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 32");
}
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + srcPos;
+ dst[dstPos + i] = (short) (0xffff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a int into an array of byte using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * Converts a long into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the long to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
- if (0 == nBytes) {
+ public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
+ if (0 == nBools) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 32) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greather or equal to than 32");
+ if (nBools - 1 + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 64");
}
- for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ for (int i = 0; i < nBools; i++) {
+ final int shift = i + srcPos;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
return dst;
}
/**
- *
- * Converts a short into an array of byte using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * Converts a long into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the long to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos,
- final int nBytes) {
+ public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
if (0 == nBytes) {
return dst;
}
- if ((nBytes - 1) * 8 + srcPos >= 16) {
- throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greather or equal to than 16");
+ if ((nBytes - 1) * Byte.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 64");
}
for (int i = 0; i < nBytes; i++) {
- final int shift = i * 8 + srcPos;
- dst[dstPos + i] = (byte) (0xff & (src >> shift));
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a long into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 64}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * Converts a long into an array of char using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the long to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit the initial value for the result String.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nHexs the number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 64}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
+ public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
if (0 == nHexs) {
return dstInit;
}
- if ((nHexs - 1) * 4 + srcPos >= 64) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greather or equal to than 64");
+ if ((nHexs - 1) * 4 + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 64");
}
final StringBuilder sb = new StringBuilder(dstInit);
int append = sb.length();
for (int i = 0; i < nHexs; i++) {
final int shift = i * 4 + srcPos;
- final int bits = (int) (0xF & (src >> shift));
+ final int bits = (int) (0xF & src >> shift);
if (dstPos + i == append) {
++append;
sb.append(intToHexDigit(bits));
@@ -1268,275 +1161,228 @@ public static String longToHex(final long src, final int srcPos, final String ds
}
/**
- *
- * Converts a int into an array of Char using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 32}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * Converts a long into an array of int using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the long to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nInts the number of ints to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0}.
+ * @throws IllegalArgumentException if {@code (nInts - 1) * 32 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length}.
*/
- public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
- return dstInit;
+ public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos, final int nInts) {
+ if (0 == nInts) {
+ return dst;
}
- if ((nHexs - 1) * 4 + srcPos >= 32) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greather or equal to than 32");
+ if ((nInts - 1) * Integer.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nInts - 1) * 32 + srcPos >= 64");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ for (int i = 0; i < nInts; i++) {
+ final int shift = i * Integer.SIZE + srcPos;
+ dst[dstPos + i] = (int) (0xffffffff & src >> shift);
}
- return sb.toString();
+ return dst;
}
/**
- *
- * Converts a short into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 16}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * Converts a long into an array of short using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the long to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + srcPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length}.
*/
- public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
- return dstInit;
+ public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos, final int nShorts) {
+ if (0 == nShorts) {
+ return dst;
}
- if ((nHexs - 1) * 4 + srcPos >= 16) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greather or equal to than 16");
+ if ((nShorts - 1) * Short.SIZE + srcPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 64");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + srcPos;
+ dst[dstPos + i] = (short) (0xffff & src >> shift);
}
- return sb.toString();
+ return dst;
}
/**
- *
- * Converts a byte into an array of Char using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the byte to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dstInit the initial value for the result String
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 8}
- * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}
+ * Converts an array of short into an int using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the short array to convert.
+ * @param srcPos the position in {@code src}, in short unit, from where to start the conversion.
+ * @param dstInit initial value of the destination int.
+ * @param dstPos the position of the LSB, in bits, in the result int.
+ * @param nShorts the number of shorts to convert.
+ * @return an int containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + dstPos >= 32}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}.
*/
- public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos,
- final int nHexs) {
- if (0 == nHexs) {
+ public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos, final int nShorts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
return dstInit;
}
- if ((nHexs - 1) * 4 + srcPos >= 8) {
- throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greather or equal to than 8");
+ if ((nShorts - 1) * Short.SIZE + dstPos >= Integer.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 32");
}
- final StringBuilder sb = new StringBuilder(dstInit);
- int append = sb.length();
- for (int i = 0; i < nHexs; i++) {
- final int shift = i * 4 + srcPos;
- final int bits = 0xF & (src >> shift);
- if (dstPos + i == append) {
- ++append;
- sb.append(intToHexDigit(bits));
- } else {
- sb.setCharAt(dstPos + i, intToHexDigit(bits));
- }
+ int out = dstInit;
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + dstPos;
+ final int bits = (0xffff & src[i + srcPos]) << shift;
+ final int mask = 0xffff << shift;
+ out = out & ~mask | bits;
}
- return sb.toString();
+ return out;
}
/**
- *
- * Converts a long into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the long to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 64}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * Converts an array of short into a long using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the short array to convert.
+ * @param srcPos the position in {@code src}, in short unit, from where to start the conversion.
+ * @param dstInit initial value of the destination long.
+ * @param dstPos the position of the LSB, in bits, in the result long.
+ * @param nShorts the number of shorts to convert.
+ * @return a long containing the selected bits.
+ * @throws NullPointerException if {@code src} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nShorts - 1) * 16 + dstPos >= 64}.
+ * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length}.
*/
- public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
- return dst;
+ public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos, final int nShorts) {
+ if (src.length == 0 && srcPos == 0 || 0 == nShorts) {
+ return dstInit;
}
- if (nBools - 1 + srcPos >= 64) {
- throw new IllegalArgumentException("nBools-1+srcPos is greather or equal to than 64");
+ if ((nShorts - 1) * Short.SIZE + dstPos >= Long.SIZE) {
+ throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 64");
}
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ long out = dstInit;
+ for (int i = 0; i < nShorts; i++) {
+ final int shift = i * Short.SIZE + dstPos;
+ final long bits = (0xffffL & src[i + srcPos]) << shift;
+ final long mask = 0xffffL << shift;
+ out = out & ~mask | bits;
}
- return dst;
+ return out;
}
/**
- *
- * Converts a int into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the int to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 32}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * Converts a short into an array of boolean using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the short to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBools - 1 + srcPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}.
*/
- public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
+ public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos, final int nBools) {
if (0 == nBools) {
return dst;
}
- if (nBools - 1 + srcPos >= 32) {
- throw new IllegalArgumentException("nBools-1+srcPos is greather or equal to than 32");
+ if (nBools - 1 + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("nBools - 1 + srcPos >= 16");
}
+ assert nBools - 1 < Short.SIZE - srcPos;
for (int i = 0; i < nBools; i++) {
final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ dst[dstPos + i] = (0x1 & src >> shift) != 0;
}
return dst;
}
/**
- *
- * Converts a short into an array of boolean using the default (little endian, Lsb0) byte
- * and bit ordering.
- *
- *
- * @param src the short to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * Converts a short into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the short to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code (nBytes - 1) * 8 + srcPos >= 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
- public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
+ public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos, final int nBytes) {
+ if (0 == nBytes) {
return dst;
}
- if (nBools - 1 + srcPos >= 16) {
- throw new IllegalArgumentException("nBools-1+srcPos is greather or equal to than 16");
+ if ((nBytes - 1) * Byte.SIZE + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 16");
}
- assert (nBools - 1) < 16 - srcPos;
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ for (int i = 0; i < nBytes; i++) {
+ final int shift = i * Byte.SIZE + srcPos;
+ dst[dstPos + i] = (byte) (0xff & src >> shift);
}
return dst;
}
/**
- *
- * Converts a byte into an array of boolean using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the byte to convert
- * @param srcPos the position in {@code src}, in bits, from where to start the conversion
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to
- * the width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 8}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length}
+ * Converts a short into an array of char using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the short to convert.
+ * @param srcPos the position in {@code src}, in bits, from where to start the conversion.
+ * @param dstInit the initial value for the result String.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nHexs the number of chars to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws IllegalArgumentException if {@code (nHexs - 1) * 4 + srcPos >= 16}.
+ * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos}.
*/
- public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos,
- final int nBools) {
- if (0 == nBools) {
- return dst;
+ public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos, final int nHexs) {
+ if (0 == nHexs) {
+ return dstInit;
}
- if (nBools - 1 + srcPos >= 8) {
- throw new IllegalArgumentException("nBools-1+srcPos is greather or equal to than 8");
+ if ((nHexs - 1) * 4 + srcPos >= Short.SIZE) {
+ throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 16");
}
- for (int i = 0; i < nBools; i++) {
- final int shift = i + srcPos;
- dst[dstPos + i] = (0x1 & (src >> shift)) != 0;
+ final StringBuilder sb = new StringBuilder(dstInit);
+ int append = sb.length();
+ for (int i = 0; i < nHexs; i++) {
+ final int shift = i * 4 + srcPos;
+ final int bits = 0xF & src >> shift;
+ if (dstPos + i == append) {
+ ++append;
+ sb.append(intToHexDigit(bits));
+ } else {
+ sb.setCharAt(dstPos + i, intToHexDigit(bits));
+ }
}
- return dst;
+ return sb.toString();
}
/**
- *
- * Converts UUID into an array of byte using the default (little endian, Lsb0) byte and bit
- * ordering.
- *
- *
- * @param src the UUID to convert
- * @param dst the destination array
- * @param dstPos the position in {@code dst} where to copy the result
- * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the
- * width of the input (from srcPos to msb)
- * @return {@code dst}
- * @throws NullPointerException if {@code dst} is {@code null}
- * @throws IllegalArgumentException if {@code nBytes > 16}
- * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}
+ * Converts UUID into an array of byte using the default (little-endian, LSB0) byte and bit ordering.
+ *
+ * @param src the UUID to convert.
+ * @param dst the destination array.
+ * @param dstPos the position in {@code dst} where to copy the result.
+ * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the width of the input (from srcPos to MSB).
+ * @return {@code dst}.
+ * @throws NullPointerException if {@code dst} is {@code null}.
+ * @throws IllegalArgumentException if {@code nBytes > 16}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length}.
*/
public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int dstPos, final int nBytes) {
if (0 == nBytes) {
return dst;
}
if (nBytes > 16) {
- throw new IllegalArgumentException("nBytes is greather than 16");
+ throw new IllegalArgumentException("nBytes > 16");
}
- longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, nBytes > 8 ? 8 : nBytes);
+ longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, Math.min(nBytes, 8));
if (nBytes >= 8) {
longToByteArray(src.getLeastSignificantBits(), 0, dst, dstPos + 8, nBytes - 8);
}
@@ -1544,22 +1390,12 @@ public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int
}
/**
- *
- * Converts bytes from an array into a UUID using the default (little endian, Lsb0) byte and
- * bit ordering.
- *
- *
- * @param src the byte array to convert
- * @param srcPos the position in {@code src} where to copy the result from
- * @return a UUID
- * @throws NullPointerException if {@code src} is {@code null}
- * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning
- * with {@code srcPos}
+ * Constructs a new instance.
+ *
+ * @deprecated Will be removed in 4.0.0.
*/
- public static UUID byteArrayToUuid(final byte[] src, final int srcPos) {
- if (src.length - srcPos < 16) {
- throw new IllegalArgumentException("Need at least 16 bytes for UUID");
- }
- return new UUID(byteArrayToLong(src, srcPos, 0, 0, 8), byteArrayToLong(src, srcPos + 8, 0, 0, 8));
+ @Deprecated
+ public Conversion() {
+ // empty
}
}
diff --git a/src/main/java/org/apache/commons/lang3/DoubleRange.java b/src/main/java/org/apache/commons/lang3/DoubleRange.java
new file mode 100644
index 00000000000..060f4116e5a
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/DoubleRange.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3;
+
+/**
+ * Specializes {@link NumberRange} for {@link Double}s.
+ *
+ *
+ * This class is not designed to interoperate with other NumberRanges
+ *
+ *
+ * @since 3.13.0
+ */
+public final class DoubleRange extends NumberRange {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a range with the specified minimum and maximum values (both inclusive).
+ *
+ *
+ * The range uses the natural ordering of the elements to determine where values lie in the range.
+ *
+ *
+ *
+ * The arguments may be passed in the order (min, max) or (max,min). The getMinimum and getMaximum methods will return the correct values.
+ *
+ *
+ * @param fromInclusive the first value that defines the edge of the range, inclusive.
+ * @param toInclusive the second value that defines the edge of the range, inclusive.
+ * @return the range object, not null.
+ */
+ public static DoubleRange of(final double fromInclusive, final double toInclusive) {
+ return of(Double.valueOf(fromInclusive), Double.valueOf(toInclusive));
+ }
+
+ /**
+ * Creates a range with the specified minimum and maximum values (both inclusive).
+ *
+ *
+ * The range uses the natural ordering of the elements to determine where values lie in the range.
+ *
+ *
+ *
+ * The arguments may be passed in the order (min, max) or (max,min). The getMinimum and getMaximum methods will return the correct values.
+ *
+ *
+ * @param fromInclusive the first value that defines the edge of the range, inclusive.
+ * @param toInclusive the second value that defines the edge of the range, inclusive.
+ * @return the range object, not null.
+ * @throws NullPointerException if either element is null.
+ */
+ public static DoubleRange of(final Double fromInclusive, final Double toInclusive) {
+ return new DoubleRange(fromInclusive, toInclusive);
+ }
+
+ /**
+ * Creates an instance.
+ *
+ * @param number1 the first element, not null.
+ * @param number2 the second element, not null.
+ * @throws NullPointerException when element1 is null.
+ * @throws NullPointerException when element2 is null.
+ */
+ private DoubleRange(final Double number1, final Double number2) {
+ super(number1, number2, null);
+ }
+
+ /**
+ * Fits the given value into this range by returning the given value or, if out of bounds, the range minimum if
+ * below, or the range maximum if above.
+ *
+ *
+ *
+ * @param element the element to test.
+ * @return the minimum, the element, or the maximum depending on the element's location relative to the range.
+ * @since 3.19.0
+ */
+ public double fit(final double element) {
+ return super.fit(element).doubleValue();
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/lang3/EnumUtils.java b/src/main/java/org/apache/commons/lang3/EnumUtils.java
index 699a2153937..513b3140ae5 100644
--- a/src/main/java/org/apache/commons/lang3/EnumUtils.java
+++ b/src/main/java/org/apache/commons/lang3/EnumUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,12 +20,18 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.stream.Streams;
/**
- *
Utility library to provide helper methods for Java enums.
+ * Provides methods for Java enums.
*
*
#ThreadSafe#
*
@@ -33,278 +39,442 @@
*/
public class EnumUtils {
- private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted";
private static final String CANNOT_STORE_S_S_VALUES_IN_S_BITS = "Cannot store %s %s values in %s bits";
- private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type";
private static final String ENUM_CLASS_MUST_BE_DEFINED = "EnumClass must be defined.";
+ private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted";
+ private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type";
/**
- * This constructor is public to permit tools that require a JavaBean
- * instance to operate.
- */
- public EnumUtils() {
- }
-
- /**
- *
Gets the {@code Map} of enums by name.
- *
- *
This method is useful when you need a map of enums by name.
+ * Validate {@code enumClass}.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @return the modifiable map of enum names to enums, never null
+ * @param the type of the enumeration.
+ * @param enumClass to check.
+ * @return {@code enumClass}.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class.
+ * @since 3.2
*/
- public static > Map getEnumMap(final Class enumClass) {
- final Map map = new LinkedHashMap();
- for (final E e: enumClass.getEnumConstants()) {
- map.put(e.name(), e);
- }
- return map;
+ private static > Class asEnum(final Class enumClass) {
+ Objects.requireNonNull(enumClass, ENUM_CLASS_MUST_BE_DEFINED);
+ Validate.isTrue(enumClass.isEnum(), S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE, enumClass);
+ return enumClass;
}
/**
- *
Gets the {@code List} of enums.
- *
- *
This method is useful when you need a list of enums rather than an array.
+ * Validate that {@code enumClass} is compatible with representation in a {@code long}.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @return the modifiable list of enums, never null
+ * @param the type of the enumeration.
+ * @param enumClass to check.
+ * @return {@code enumClass}.
+ * @throws NullPointerException if {@code enumClass} is {@code null}.
+ * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values.
+ * @since 3.0.1
*/
- public static > List getEnumList(final Class enumClass) {
- return new ArrayList(Arrays.asList(enumClass.getEnumConstants()));
+ private static > Class checkBitVectorable(final Class enumClass) {
+ final E[] constants = asEnum(enumClass).getEnumConstants();
+ Validate.isTrue(constants.length <= Long.SIZE, CANNOT_STORE_S_S_VALUES_IN_S_BITS, Integer.valueOf(constants.length), enumClass.getSimpleName(),
+ Integer.valueOf(Long.SIZE));
+ return enumClass;
}
/**
- *
Checks if the specified name is a valid enum for the class.
- *
- *
This method differs from {@link Enum#valueOf} in that checks if the name is
- * a valid enum without needing to catch the exception.
+ * Creates a long bit vector representation of the given array of Enum values.
*
- * @param the type of the enumeration
- * @param enumClass the class of the enum to query, not null
- * @param enumName the enum name, null returns false
- * @return true if the enum name is valid, otherwise false
- */
- public static > boolean isValidEnum(final Class enumClass, final String enumName) {
- if (enumName == null) {
- return false;
- }
- try {
- Enum.valueOf(enumClass, enumName);
- return true;
- } catch (final IllegalArgumentException ex) {
- return false;
- }
- }
-
- /**
- *