Reminder Operator Returns Negative Value in Java
The %
operator is the reminder operator in Java.
In other languages, it may be called modulo operator.
”%”, which divides one operand by another and returns the remainder as its result.
It seems a simple operator, by looking at example code like this, 10 % 7 = 3
.
However, the %
operator may return a negative value.
assertEquals(-1, -9 % 2, "return negative value here");
assertEquals(1, 9 % -2, "return positive value here");
It’s because Java’s reminder implementation uses “truncated division”. See details in this Wiki page.
The “truncation (integer part)” of -9 / 2
, i.e. -4.5
, is -4
. So,
-9 % 2 = -9 - 2 * (-4) = -9 - (-8) = -1
For the 9 % -2
case, the “truncation” is also -4
. However,
9 % -2 = 9 - (-2) * (-4) = 9 - 8 = 1
A Problem
Sometime, this %
returning negative behavior may cause problems.
var batches = 10;
// ... some RxJava code
.groupBy(input -> Objects.hash(input) % batches)
//...
For example, in above code you may want to split your work into 10 batches.
However, because the Objects.hash()
may return negative hash code,
Objects.hash(input) % 10
has 19 possible values (integers), from -9 to 9.
So unexpectedly, your work is split int 19 batches.
A Rescue
Java 8 provides a Math.floorMod() method, which can be used in situations like above. According to its Javadoc,
If the signs of the arguments are the same, the results of floorMod and the % operator are the same.
If the signs of the arguments are different, the results differ from the % operator.
floorMod(+4, -3) == -2; and (+4 % -3) == +1
floorMod(-4, +3) == +2; and (-4 % +3) == -1
floorMod(-4, -3) == -1; and (-4 % -3) == -1
The floorMod(x, y)
is calculated using below relationship.
floorDiv(x, y) * y + floorMod(x, y) == x
And for the Math.floorDiv() method, its Javadoc says
Returns the largest (closest to positive infinity) int value that is less than or equal to the algebraic quotient.
For example, floorDiv(-4, 3) == -2, whereas (-4 / 3) == -1.
Given dividend is -4 and divisor is 3, its algebraic quotient is -1.333333.
“The largest (closest to positive infinity) int value that is less than or equal to” -1.333333
is -2, not -1 which is larger than the quotient.
Therefore, floorDiv(-4, 3) == -2
.
floorMod(-4, 3) = -4 - floorDiv(-4, 3) * 3 = -4 - (-2)*3 = 2
Compare Two OffsetDateTime of the Same Instant
For two Java OffsetDateTime objects of the same instant, but with different
timezone offset, to check whether they represent the same point in time,
the isEqual
method should be used.
var date1 = OffsetDateTime.parse("2008-12-03T11:00+01:00");
var date2 = OffsetDateTime.parse("2008-12-03T12:00+02:00");
date1.isEqual(date2); // the result is true
date1.equals(date2); // the result is false
date1.compareTo(date2); // the result < 0
In the above code, both of the OffsetDateTime objects represent “2008-12-03T10:00Z”.
However, the equals
or the compareTo
method will tell these two object are not “equal”.
The OffsetDateTime class uses a field of LocalDateTime and a field of ZoneOffset
to represent an instant. Its equals
method cares about whether all these field
of two objects are same or not. Obviously, fields of date1
are not equals with
ones of date2
.
The compareTo
has same behavior as equals
.
It is “consistent with equals”, as defined by Comparable.
As per Javadoc of OffsetDateTime, what isEqual
does is dateTime1.toInstant().equals(dateTime2.toInstant())
.
That is OffsetDateTime object are convert to Instant object first, and use
the equals
of Instant for comparison.
From the Javadoc of Instant,
An instantaneous point on the time-line.
the class stores a long representing epoch-seconds and an int representing nanosecond-of-second, … The epoch-seconds are measured from the standard Java epoch of 1970-01-01T00:00:00Z
An Instant object has no timezone info stored, only epoch of fixed UTC timezone stored, a long and a int.
Side note: what’s the different between ZonedDateTime and OffsetDateTime
The major difference is that ZonedDateTime knows Daylight saving time (DST), while OffsetDateTime does not. It’s because OffsetDateTime only stores simple offset to UTC, while ZonedDateTime stores much richer timezone info.
Git Command Examples
- Checkout a Remote Branch in Local
- Print the Short Commit SHA1 of a Git Tag
- Fix the
^M
Character Shown ingit diff
Result - Prune stale remote branches in local repository
Checkout a Remote Branch in Local
$ git checkout --track origin/master
The above command creates a local branch with the same name, i.e. master
, as the remote branch,
and let the local branch track the remote one.
“Tracking” means when run git push
, Git knows where it pushes changes into.
Some notes from git checkout --help
,
As a convenience, –track without -b implies branch creation
-t, –track
When creating a new branch, set up “upstream” configuration.
If no -b option is given, the name of the new branch will be derived from the remote-tracking branch
Print the Short Commit SHA1 of a Git Tag
# Assume the Git tag is "0.1.0"
$ git rev-list -n 1 0.1.0 --pretty=format:"%h" | tail -1
c363005
The tag “0.1.0” points to the commit c363005
.
Use %H
if the full SHA1 is needed.
(Search “placeholder” in git show --help
for the document of format:<string>
.)
Add --abbrev
option, like --abbrev=8
, if a fixed width SHA1 is needed.
Fix the ^M
Character Shown in git diff
Result
Sometimes, when run git diff
, it prints ^M
at the end of some lines.
The ^M
character represents a carriage-return character, i.e. CRLF
, the new line character in Windows.
You may see ^M
before, if you use Vim to edit some files coming for Windows/DOS.
Seeing ^M
in the git diff
result means the same line was ended with CRLF
but now
with LF
, or vice versa.
Usually, a Git repository should be configured in a way that all text files committed
into the repository end with LF
, while files checked out end the local machine specific
endings, i.e. LF
in Unix and CRLF
in Windows machines. So that ^M
would not be seen
in git diff
. To fix a repository’s configuration, add a .gitattributes
file with content
like
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Declare files that will always have CRLF line endings on checkout.
*.bat text eol=crlf
“Renormalize” all the files with updated configuration.
$ git stash -u
$ git add --renormalize .
$ git status
$ git commit -m "Normalize line endings"
$ git stash pop
See this GitHub doc, Configuring Git to handle line endings, for more details.
Prune stale remote branches in local repository
As time goes by, local repository may have many remote branches, which were actually
deleted in remote repository. For example, in GitLab someone’s feature branch is usually
deleted while it’s merged by a merge request. However, these origin/feat-x
,
origin/feat-y
branches are kept in your local repository since they’re fetched.
To delete these stale remote branches in local all at once, run
$ git remote prune origin
# Or,
$ git fetch --prune
It’s said in git remote --help
,
might even prune local tags that haven’t been pushed there.
So it’s a good idea to run above commands with --dry-run
option first.
Delete one remote branch by git branch -r -d origin/feat-x
.
Mod in Java Produces Negative Numbers
Mod in Java produces negative numbers
The problem here is that in Python the % operator returns the modulus and in Java it returns the remainder. These functions give the same values for positive arguments, but the modulus always returns positive results for negative input, whereas the remainder may give negative results.
What’s the difference between “mod” and “remainder”?
-21 mod 4 is 3 because -21 + 4 x 6 is 3.
But -21 divided by 4 gives -5 with a remainder of -1.
Import Files in Protocol Buffer
A Java project contains protocol buffer files (to define gRPC API).
It uses protobuf-gradle-plugin to compile the protocol buffer files.
By default this Gradle plugin reads protocol buffer source files from the src/main/proto/
directory.
The structure of the src/main/proto/
is like below.
.
├── foo
│ ├── bar
│ │ └── def.proto
│ ├── common
│ │ └── common.proto
Assume in the foo/bar/def.proto
file, it needs to import message types defined in the
foo/common/common.proto
file. To do it, in the foo/bar/def.proto
file, add lines like below.
syntax = "proto3";
package foo.bar;
import "foo/common/common.proto";
message BarType {
// use full qualified name to refer to CommonTypeA, not just `CommonTypeA`
// (assume the package name is "foo.common")
foo.common.CommonTypeA a = 1;
}
A import statement using relative path like import "../../common.proto";
does not work. Because the protocol compiler
does not search files in the “upper” directories. It only searches in directories provided by the -I/--proto_path
options or the directory in which the compiler was invoked if the -I
option not given.
The protocol compiler searches for imported files in a set of directories specified on the protocol compiler command line using the -I/–proto_path flag. If no flag was given, it looks in the directory in which the compiler was invoked. In general you should set the –proto_path flag to the root of your project and use fully qualified names for all imports.
The protobuf-gradle-plugin sets src/main/proto/
to the -I
option when invokes protoc
. It can be observed from the Gradle
info log, ./gradlew build -i
. Therefore, for the statement import "foo/common/common.proto";
, the protoc
will successfully
find the imported file under the foo/common
directory of the src/main/proto/
.
(Usually IntelliJ IDEA knows that the src/main/proto/
is the path to search imported files.
If not, add “Custom include paths” in Preferences -> Protobuf Support
.)
More documentation about the --proto_path=IMPORT_PATH
option.
IMPORT_PATH
specifies a directory in which to look for .proto files when resolving import directives. If omitted, the current directory is used. Multiple import directories can be specified by passing the--proto_path
option multiple times; they will be searched in order.-I=_IMPORT_PATH_
can be used as a short form of--proto_path
.
The jq Command Examples
- The
keys
builtin function - Array/Object Value Iterator: .[]
exp as $x | ...
and String Interpolation- More Complex Expression in String interpolation
- Array construction:
[]
- Object Construction:
{}
- Object Construction:
{}
and Array construction:[]
- The
sort
function - The
sort_by
function - Select/Filter
- Multiple Conditions in
select
Some jq
examples. All quotes are from the jq manual.
A sample json file is as below.
$ cat sample.json
{
"apple-weight": [
60
],
"orange-weight": [
50
],
"banana-weight": [
20,
35
]
}
The keys
builtin function
$ jq '. | keys' sample.json
[
"apple-weight",
"banana-weight",
"orange-weight"
]
The builtin function keys, when given an object, returns its keys in an array.
Array/Object Value Iterator: .[]
$ jq '. | keys[]' sample.json
"apple-weight"
"banana-weight"
"orange-weight"
If you use the .[index] syntax, but omit the index entirely, it will return all of the elements of an array.
Running .[] with the input [1,2,3] will produce the numbers as three separate results, rather than as a single array.
You can also use this on an object, and it will return all the values of the object.
exp as $x | ...
and String Interpolation
$ jq '. | keys[] as $k | "\($k), \(.[$k])"' sample.json
"apple-weight, [60]"
"banana-weight, [20,35]"
"orange-weight, [50]"
The expression
exp as $x | ...
means: for each value of expression exp, run the rest of the pipeline with the entire original input, and with $x set to that value. Thus as functions as something of a foreach loop.
The '. | keys[] as $k | "\($k), \(.[$k])"'
means for each value of . | keys[]
, which are “apple-weight”, “banana-weight” and “orange-weight”,
run the rest of pipeline, i.e. "\($k), \(.[$k])"
, which is string interpolation.
String interpolation - (foo)
More Complex Expression in String interpolation
$ jq '. | keys[] as $k | "\($k), \(.[$k][0])" ' sample.json
"apple-weight, 60"
"banana-weight, 20"
"orange-weight, 50"
\(.[$k][0])
is replaced with the value of .["apple-weight"][0]
.
Array construction: []
$ jq -c '. | keys[] as $k | [$k, .[$k][0]] ' sample.json
["apple-weight",60]
["banana-weight",20]
["orange-weight",50]
$ jq '[ . | keys[] as $k | [$k, .[$k][0]] ] ' sample.json
[
[
"apple-weight",
60
],
[
"banana-weight",
20
],
[
"orange-weight",
50
]
]
If you have a filter X that produces four results, then the expression [X] will produce a single result, an array of four elements.
The . | keys[] as $k | [$k, .[$k][0]]
produces three results, enclosing it with []
produces an array of these three elements.
Object Construction: {}
$ jq ' . | keys[] as $k | {category: $k, weight: .[$k][0]} ' sample.json
{
"category": "apple-weight",
"weight": 60
}
{
"category": "banana-weight",
"weight": 20
}
{
"category": "orange-weight",
"weight": 50
}
Object Construction: {}
and Array construction: []
$ jq '[ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] ' sample.json
[
{
"category": "apple-weight",
"weight": 60
},
{
"category": "banana-weight",
"weight": 20
},
{
"category": "orange-weight",
"weight": 50
}
]
The sort
function
$ jq '[ . | keys[] as $k | [$k, .[$k][0]] ] | sort ' sample.json
[
[
"apple-weight",
60
],
[
"banana-weight",
20
],
[
"orange-weight",
50
]
]
The sort functions sorts its input, which must be an array.
Values are sorted in the following order:
null
,false
,true
, …
The [ . | keys[] as $k | [$k, .[$k][0]] ]
is an array of three elements, each of which itself is an array.
These three elements, according to the manual, are sorted “in lexical order”.
The sort_by
function
$ jq '[ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] | sort_by(.weight) ' sample.json
[
{
"category": "banana-weight",
"weight": 20
},
{
"category": "orange-weight",
"weight": 50
},
{
"category": "apple-weight",
"weight": 60
}
]
sort_by(foo) compares two elements by comparing the result of foo on each element.
The [ . | keys[] as $k | {category: $k, weight: .[$k][0]} ]
is an array of three objects.
The | sort_by(.weight)
sorts these three objects by comparing their weight
property.
The final result is still an array, but sorted.
Select/Filter
$ jq '[ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] | sort_by(.weight) | .[] | select(.weight >= 50) ' sample.json
{
"category": "orange-weight",
"weight": 50
}
{
"category": "apple-weight",
"weight": 60
}
The function select(foo) produces its input unchanged if foo returns true for that input, and produces no output otherwise.
The [ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] | sort_by(.weight)
produces a sorted array.
The following .[]
, i.e. array iterator, feeds select(.weight >= 50)
with three elements of that array.
The final result is elements whose weight
is equal or larger than 50
.
The command below, using map
, produces the same result.
$ jq '[ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] | sort_by(.weight) | map(select(.weight >= 50)) ' sample.json
[
{
"category": "orange-weight",
"weight": 50
},
{
"category": "apple-weight",
"weight": 60
}
]
Multiple Conditions in select
$ jq '[ . | keys[] as $k | {category: $k, weight: .[$k][0]} ] | sort_by(.weight) | .[] | select( (.weight >= 50) and (.weight < 60)) ' sample.json
{
"category": "orange-weight",
"weight": 50
}
Avoid Wrong Tracking When Create Branches in Git
Just made a mistake to push commits to a wrong remote branch. Below is the detail.
- Need to create a new branch
br-x
, which needs to be based on the newest remotedev
branch. - Run
git fetch
to get newest change from the remote. - Run
git checkout -b br-x origin/dev
to create branchbr-x
. - Change and commit files in branch
br-x
. - Run
git push origin -u br-x
to push commits to the remote.
In step 3, the origin/dev
is used to as the “start-point” of the new br-x
branch. As per git branch --help
,
When a local branch is started off a remote-tracking branch, Git sets up the branch (specifically the
branch.<name>.remote
andbranch.<name>.merge
configuration entries) so that git pull will appropriately merge from the remote-tracking branch. This behavior may be changed via the global branch.autoSetupMerge configuration flag.
In other words, the git checkout -b br-x origin/dev
not only create a new br-x
branch, but also let the br-x
track
the remote dev
branch. As a result, in step 5, the git push origin -u br-x
doesn’t push commits into a same-name remote branch.
However, it pushes commits into the remote dev
branch, which the local br-x
is tracking since its creation.
The remote dev
branch is accidentally modified. 😞
To avoid it, one method is use the local dev
branch as the “start-point” in step 3. Consider the local dev
may be behind
the remote dev
. You may have to switch to the local dev
and git pull
to update it first.
Another method is using --no-track
option, i.e. git checkout -b --no-track br-x origin/dev
.
A more thorough method is using git config --global branch.autoSetupMerge false
to change the default behavior of Git.
When branch.autoSetupMerge
is false
, when create a branch, Git will not setup its tracking branch even if the “start-point” is a remote-tracking branch.
From more details search “branch.autoSetupMerge” in git config --help
.
For what is “remote-tracking” branch, check this link. Simply put,
Remote-tracking branch names take the form
<remote>/<branch>
.
Enable Junit 5 Test Cases Based on Java System Properties
JUnit 5 supports disabling test cases via the @Disabled
annotation.
Sometimes, you may want some cases to be conditionally disabled or enabled.
JUnit 5 provides many annotations to support conditional test execution, like @EnabledOnOs(MAC)
, @DisabledOnJre(JAVA_8)
and @EnabledIfEnvironmentVariable
.
Let’s say, a test case only runs when a Java system property is set to a certain value.
To do it, add @EnabledIfSystemProperty
onto the test case.
@Test
@EnabledIfSystemProperty(named = "foo.enabled", matches = "on")
void fooTest() {
}
The fooTest
runs only when the foo.enabled
system property is set to on
.
To run this test case via Gradle, type the command below.
./gradlew test --tests '*.fooTest' -i -Dfoo.enabled=on
To make the JVM running the test case know the Java system property passed to the JVM running Gradle, add below lines
in the build.gradle
file.
test {
systemProperty "foo.enabled", System.getProperty("foo.enabled")
}
How to Add Disqus to a Rails Application
Copy the “universal code” of your Disqus account from your account’s admin page,
https://<your-account>.disqus.com/admin/install/platforms/universalcode/
.
The universal code is like below.
<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://<your-account>.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
Paste it into where the Disqus comments block should display.
Set this.page.url
and this.page.identifier
and uncomment these lines to “avoid split threads and missing comments”.
For example, for this site they are set like below.
// tested in Rails 5
this.page.url = '<%= url_for host: "https://onefeed.xyz" %>';
this.page.identifier = '<%= @post.slug %>';
Update
If the Rails application is deployed behind a Nginx, where SSL/Https is enabled, and listening on an internal port like 3000.
The <%= url_for host: "https://onefeed.xyz" %>
above will generate values like http://onefeed.xyz:3000/posts/how-to-add-disqus-to-a-rails-application
.
To correct the port and the schema, use the code below.
this.page.url = '<%= url_for host: "onefeed.xyz", port: nil, protocol: "https" %>';
It generates URLs like https://onefeed.xyz/posts/how-to-add-disqus-to-a-rails-application
.
Check more in url_for API.
Different Emails Addresses for Different Git Repositories
Sometimes, we may want to set up different user emails and user names for different Git repositories.
For example, in your personal computer, the user.email
is set to your personal email address globally.
While committing to your corporate repositories in the personal computer, your corporate email address should be used in the
commits. Or you’re working on personal projects on the corporate computer, need to use the personal email for the personal
repositories.
Configure Email Address for A Repository
The simplest way is going to each repository, and configuring the user email for each repository specifically.
$ cd /path/to/repo-foo
$ git config user.email email.foo@example.com
$ git config user.name name-foo
The above git config
commands write the user.email
setting into the .git/config
file under the repository.
From git help config
, when writing configuration, by default it’s writing to the repository-local configuration file.
When writing, the new value is written to the repository local configuration file by default, and options –system, –global, –worktree, –file
can be used to tell the command to write to that location
Examine the Email Address for a Repository
$ cd /path/to/repo-foo
$ git config --list | grep user.email
user.email=email.bar@example.com
user.email=email.foo@example.com
The git config --list
above prints more than one user.email
values. It’s because, without additional options, the
git config --list
outputs configuration “merged” from system, global and local.
From git help config
,
When reading, the values are read from the system, global and repository local configuration files by default
The git config --list
is a read operation.
The first user.email
value above is from “global”, i.e. ~/.gitconfig
.
Run git config --list --local | grep user.email
to check the repository-local email configuration.
Instead of piping config --list
and grep
, use git config --get user.email
to save some typings.
$ cd /path/to/repo-foo
$ git config --get user.email
user.email=email.foo@example.com
From git help config
, --get
returns
the last value if multiple key values were found.
Here, the last value is the email from repository-local configuration.
The --get
can be further omitted, git config user.email
has the same result.
And git config --get-all user.email
is same as git config --list | grep user.email
.
Conditional Includes
For new cloned repositories, it’s often to forget to configure the right email addresses for them.
The “conditional includes” feature of the git config
can save us from this problem.
For example, in your personal computer, all corporate repositories are under ~/corp-repo/
.
Add a text file called corp-gitconfig
there, and edit it as below.
[user]
name = user-name-for-corp-prj
email = email-add@your-corp.com
Add below lines in the global git config file, i.e. ~/.gitconfig
.
[includeIf "gitdir:~/corp-repo/"]
path = ~/corp-repo/corp-gitconfig
Now if a new repository is cloned user ~/corp-repo/
, the email for that repository is automatically set to
email-add@your-corp.com
.