Java Random Notes
Until I find time to get more organized, here are a number of miscellaneous
notes assembled when I find answers to Java questions and don't want to have to
go looking for them again.
Some terminology
Constants in Java...
public class Clazz
{
private final static String PATHNAME = "src/test/resources/"; // class constant
private final String FILENAME = "test.dat"; // instance constant
private List< String > barNames; // instance variable
private void bar( final String barName ) // constant parameter
{
int counter; // local variable
final double PI = "3.14"; // local constant
for( final String name : barNames ) // local "constant" (within code block)
...
}
}
The Java Virtual Machine
At its core, the Java virtual machine (JVM) consists of the following
components:
Heap
Stack
PermGen and method area
Just-in-time (JIT) compiler
Code cache
The heap is where memory is allocated for every new operator you use during the
application code development stage.
Local variables which remain within the scope of a method are stored on the
stack. As a method or block in a method goes out of scope, those variables are
removed. (Note too that once Java objects no longer have live references to
them, they are garbage-collected.)
PermGen space stores class and method-level data as well as static variables
that are defined by the application. A method area is in PermGen and stores all
method, field and constant pool details of the application.
The JIT and the code cache go hand-in-hand. The JVM at its core interprets and
converts the Java byte code into assembly code at run-time. Interpreting is a
relatively slow process because the code is converted from byte code to machine
code on the fly every time a portion of your application code is executed. This
is where the JIT compiler swings into action:
The JIT compiler analyzes the application code at run-time to understand which
methods can be categorized as "hot" methods. Hot means code fragments that are
accessed more frequently. Conceptually, the JIT compiler has a counter for each
method executed in order to understand the frequency of usage. When the
counter's value reaches a defined threshold, the method becomes eligible to be
compiled by the JIT compiler to assembly which is then stored in the code
cache. From then on, whenever the JIT compiler comes across a call to such a
pre-compiled and cached method, it will no longer try to reinterpret it, but
will use the already compiled assembly code. This gives the application an
obvious performance boost.
Links
Got Java?
Because I work on Linux, in the past years I've migrated to using OpenJDK.
However, when I need Sun's Java (no, I don't mean Oracle's—I'm still a
little in denial about that), I go to
http://java.sun.com . There I can get
it for any platform, including Apple Macintosh OS X.
Because I write software in Java, I download a JDK "privately" which is to say
that I put it locally to my user, on a path like
/home/russ/dev/jdk1.7.0_51 . On Macintosh OS X, which I think give one
little-to-no say in the matter, this apparently ends up being more like
/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home . (I
don't use Macintosh, but one day I might again so this isn't completely
irrelevant.)
Setting up JAVA_HOME ...
I do this from .profile . I usually maintain a private JDK locally for
use by IntelliJ (or Eclipse back in the day) so that, when I'm developing in
Java, there are no surprises.
# set up JAVA_HOME...
if [ -e "$HOME/dev/jdk-alternative" ]; then
# ...to my private copy if present:
export JAVA_HOME="$HOME/dev/jdk-alternative/"
else
# ...or to the one on my Linux Mint/Ubuntu system:
export JAVA_HOME="/usr/lib/jvm/default-java/"
fi
Script finding and isolating Java version
Here .
Some defintions from Javaland
EAR
E nterprise ar chive . An archive containing the
enterprise-level Java bean modules.
JAR
J ava ar chive . Collection of .class files
compiled from .java files plus resources (like properties
files) and libraries (more .jar files).
WAR
W eb ar chive . Collection of JSPs (.jsp
files), .html files, even graphics and other files necessary
to the web application.
NAR
N iFi ar chive . Collection of Apache NiFi standard
and/or custom processors.
hs_err_pidXXX.log file
...where XXX is the process id (pid ), this is Java's (the JVM's)
fatal-error log, created with information and the state obtained at the moment of
the fatal error.
The JVM option, -XX:ErrorFile=path may be used to specify where
this file is created. Otherwise, it's created a) in the working directory of the
process assuming adequate space, filesystem permissions and no other issues, or
it's created on /tmp . The JVM always attempts to create this file
(and, if it fails, worse stuff than just a crashed Java application is afoot on the
system).
It's always safe to remove this file when you find it since, if you see it, it's
for a crash that's already happened, it was per-pid , the JVM no
longer expects to use it and will just create another (even if the same pid
is used) when a fatal error occurs.
Utility methods...
A collection of utility methods isn't OOP (with a capital OOP). These methods
should be static since their behaviour is not dependent on any specific
instance of attributes.
Use of static ...
A static variable in a class becomes a single instance for all
instantiations of objects of that type. If changed by one, it's changed for all
objects. static final will ensure its inability to be modified.
Declare immutable constants as static final . This guards against
inadvertant modification and permits the compiler to perform optimizations in
the use of those values.
Identifier case...
Use camel-back, lower-case initial in the names of methods and non-constant
variables.
Width of characters...
A char cannot be safely converted to byte .
Flow-control...
Never use exceptions for flow-control.
Use of .class ...
String className = ASConfig.class.getName();
Given <class-type> .class. <method>
.class gets the Class object for the class-type and calls the indicated
method. In the sample above, the class name is returned.
See
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.8.2
Accessors and mutators
..are formal names for getters and setters.
Conversions
int to String
int x = 99;
String X = Integer.toString( x );
// or
String X = "" + x;
JUnit testing
See junit.html .
Integers in Java
Type
Size
Range
name
bytes
bits
minimum
maximum
byte
1
8
-128
+127
short
2
16
-32,768
+32,767
int
4
32
-2,147,483,648
+2,147,483,647
long
8
64
-9,223,372,036,854,775,808
+9,223,372,036,854,775,807
Instance variable instantiation
Consider the following class and subclass which illustrate a bizarre point of
instance variable initialization. It might be a long time if ever someone
actually suffers from this problem, but it makes a useful observation on
initialization. The explanation here is a bit awkward and over-stated, but
clear, I think.
class Abc
{
public Abc( Object o )
{
assignValue( o );
}
public void assignValue( Object o )
{
// do nothing...
}
}
public class Test extends Abc
{
public Object x = null;
public Test( Object o )
{
super( o );
}
public void assignValue(Object o)
{
x = o;
System.out.println( "x in assignValue: " + x );
}
public static void main( String args[] ) throws CloneNotSupportedException
{
Test t = new Test( "Test" );
System.out.println( "t: " + t.x );
}
}
Output:
x in assignValue: Test
t: null
The output happens because the initialization:
public Object x = null;
executes after the constructor. So...
x = 0;
gets overwritten by
public Object x = null;
The secret is that the compiler in fact arranges to call the explicitly invoked
superclass constructor before the (local) constructor will get executed.
The initializations done as part of the class instance variable declarations
are part of and occur before the (local) construction process. In our example,
they occur implicitly before the statements in the (subclass) constructor, with
the exception of the superclass constructor invocation as noted.
Therefore, execution order is not straightforward as it is in C. Hence, here
the null initialization runs after the local class' call of its superclass
constructor. The compiler in essence absorbs the
super( o );
statement and runs it before any other constructor statements as well as even
before applying the initializations stated in the instance variable
declarations.
See
http://forums.sun.com/thread.jspa?forumID=31&threadID=5260093 .
I/O
Here's a good site for sample code:
http://www.exampledepot.com/egs/java.io/pkg.html
See also sample code in com.etretatlogiciels.samples.fileio.
The finally clause
Use this to close streams, file handles, database connections, etc.
StreamUtils.close() is your short-hand friend for the first case.
Properties properties = new Properties();
FileInputStream is = null;
try
{
is = new FileInputStream( path );
properties.load( is );
}
catch( FileNotFoundException e )
{
System.out.println( e.getMessage() );
}
catch( IOException e )
{
System.out.println( e.getMessage() );
}
finally
{
StreamUtils.close( is );
}
PipeStream
Research this class for transforming an input stream into an output stream and
vice-versa.
Reader versus Stream
In Java I/O, a file or other device may be opened on a stream and somewhere in
the layer cake that wraps the device may be a reader. A reader augments a
stream in that it deals with characters (UTF-8, etc.) rather than bytes.
Synchronization in Java
This is not an exhaustive treatment of concurrency solutions in Java. It is a
simple treatment, from a C programmer's mentality, of the Java keyword,
synchronized . Java uses this keyword in two ways.
Synchronized blocks
The synchronized keyword is used to synchronize a block of
executable statements by referring to an object. This object becomes like a
mutex in procedural programming languages: executing all other blocks with
reference to object is serialized:
Object object = new Object();
synchronized( object )
{
do something with object ;
}
How it works
On its face, object is not any kind of mutex, condition variable,
reader-writer lock, barrier or other synchronization primitive that you would
expect to declare in a procedural language to manage your protected data in
parallel. But in fact, every Java object contains a lock within itself. This
lock is formally referred to as a monitor . When the compiler sees
synchronized in this situation, it generates code to use the
object's monitor.
Synchronized methods
The synchronized keyword is also used to synchronize goings on in
a method. This is also like controlling execution of the method based on a
mutex, but the object is implied this rather than explicit.
synchronized void makeSomeoneHappy ()
{
do something to make someone happy with several objects;
}
All synchronized methods share the same mutex (this , as noted).
The above is directly equivalent to:
void makeSomeoneHappy ()
{
synchronized( this )
{
do something to make someone happy with several objects;
}
}
Watch out!
A private member variable in a class isn't safe unless all methods touching it
are explicitly synchronized. A public member variable would practically never
be safe. In the following class, x is safe, but y is not even
though their manipulating methods are synchronized.
public class TwoCounters
{
private int x = 0;
public int y = 0;
public synchronized getX () { return this.x ; }
public synchronized incX () { this.x ++; }
public synchronized zeroX (){ this.x = 0; }
public synchronized getY () { return this.y ; }
public synchronized incY () { this.y ++; }
public synchronized zeroY (){ this.y = 0; }
}
This is because code outside this class can freely access y whereas an
attempt to access x would be rebuffed by the compiler:
TwoCounters counter = new TwoCounters ();
counter.y = 99; PASSES COMPILER, BUT A BAD IDEA!
counter.x = 99; COMPILATION ERROR!
The distinction between the two methods of synchronization just contrasted is
that in the second case, no actual, explicit object is needed in writing the
code to perform serialization. There is no need to create object .
Instead, the implied object, this , is used.
(Yup, this is absolutely the first time in over a decade of writing HTML
that I have used the <blink> tag: very annoying, isn't it?)
Deadlocking
Between correctly synchronized methods in diverse classes deadlocks can easily
occur, in particular, the ABBA . The following is the scenario.
Thread A enters a synchronized method for class Foo . It holds the
monitor for Foo 's this . Let's say that thread A
blocks momentarily on some I/O operation.
Thread B enters a synchronized method for class Bar . It holds the
monitor for Bar 's this . Thread B also knows about
the same instance of Foo as thread A and attempts to enter one
of Foo 's synchronized methods. Foo 's monitor is
contested because thread A already has it.
Thread A wakes up from its I/O operation and, having a reference to the
instance of Bar that thread B already has locked, decides to
attempt to enter one of Bar 's synchronized methods.
Thread A is blocked on a monitor held by thread B and thread B is blocked
on a monitor held by thread A.
This sort of nightmare is best prevented by careful design. The temptation by
bad engineers in a procedural language might be to test whether a lock is going
to be contested before attempting to use it and, indeed, it is sometimes
impossible to do otherwise. However, all efforts to design logic to avoid doing
this should be made. Moreover, as noted next, it was not possible prior to Java
1.5 to perform a try-lock .
More traditional locking in Java
Starting (only) in Java 1.5, a new interface, Lock , is provided to
mimic not only mutexes in use in other, especially procedural languages, but
also try-locking mutexes, condition variables and reader-writer locks.
Without giving an implementation here (because that is how one chooses to
implement a mutex versus a condition variable versus a reader-writer or other
kind of lock), this example shows how it is used:
Lock l = new ...();
l .lock();
try
{
do something with resources controlled by lock l ;
}
finally
{
l .unlock();
}
This usage is unsurprising and recognizable to any C programmer. The reason for
this to exist (finally) in Java is that it gives greater flexibility (if also
imposing the inelegant coding duty of maintaining the lock just as in C).
Using synchronized does not give you the finer control to do
something else in the case the object is contested: you are blocked on
permanently on the object (explicit object or implicit
this ) until the thread that has it locked yields it. Hence the
utility of this new interface.
Managed beans (and JSF)
In Java, a managed bean is a resource running in the Java virtual machine (JVM)
used for getting and setting application configuration (pull); for collecting
statistics (also a pull operation), e.g.: performance, resource usage,
problems; and notifying events (push), e.g.: faults and state changes.
A good article with much better examples on this topic than those below can be
found
here .
A standard managed bean often implements a business interface containing
setters and getters for the attributes and the operations (or methods). There
are other sorts of managed beans.
The managed bean is also involved in inversion of control (dependency
injection) and the POJO (plain-old Java object).
Managed beans and JavaServer Faces (JSF)
Before server-side Java development became the norm, developers managed all of
their classes manually. Contemporarily, Java server "containers" (like Tomcat)
have become responsible for running applications and POJOs have come back into
popularity because they are so simple (as compared to Enterprise JavaBeans) and
useful for performing dependency injection (formerly called "inversion of
control" or IoC). The JSF managed bean facility is also an IoC framework that
makes management of JavaBeans or POJOs easy for JSF developers.
Control of instantiation
The first item of business for IoC is being able to manage instantiation of
Java objects. Originally, this was done in a page using JSP's
<jsp:usebean> that instantiated a bean for a specified scope.
This is now done using faces-config.xml and any Java class with a
no-argument constructor may be registered. Imagine a POJO thus:
public class TemperatureConverter
{
private double celsius = 0.0;
private double fahrenheit = 0.0;
private boolean initial = true;
public double getCelsius() { return celsius; }
public void setCelsius( double celsius ) { this.celsius = celsius; }
public double getFahrenheit() { return fahrenheit; }
public boolean getInitial() { return initial; }
public String reset()
{
initial = true;
fahrenheit = 0;
celsius = 0;
return "reset";
}
public String celsiusToFahrenheit()
{
initial = false;
fahrenheit = ( celsius * 9 / 5 ) + 32;
return "calculated";
}
}
The dead give-away that this is a bean is:
no-argument constructor
getter(s) and setter(s)
In faces-config.xml , the bean, which is otherwise coded as above (no
surprise) and included in the application as a simple Java object (POJO), is
registered thus:
<managed-bean>
<managed-bean-name> temperatureConverter </managed-bean-name>
<managed-bean-class> mypackage.TemperatureConverter </managed-bean-class>
<managed-bean-scope> session </managed-bean-scope>
<managed-property>
<property-name> celsius </property-name>
<value> 37.0 </value>
</managed-property>
<managed-property>
<property-name> fahrenheit </property-name>
<value> 98.6 </value>
</managed-property>
</managed-bean>
temperatureConverter is sort of arbitrarily named, but follows a common
convention of dropping the first letter of the class to lower-case (since it is
used in JSF as an indentifier).
In addition, the implicit "properties" of the bean, celsius and
fahrenheit can be the target of initialization in the same
faces-config.xml file as shown in the example above where the imaginary
Celsius-to-Fahrenheit calculator will start up set at the temperature of a
human body.
faces-config.xml is found in the typical web application at
WEB-INF . For example, in Eclipse by default this is
project-name/WebContent/WEB-INF/faces-config.xml . In the example above,
the Java code is located at
project-name/src/mypackage/TemperatureConverter.java .
Dependency handling
The ability to handle interdependence between Java objects is another
requirement of IoC. JSF doesn't handle cyclical dependencies, but managed beans
can refer to each other using expression language.
Life-cycle support
Another requirement of IoC is support of the life-cycle of, say, HTTP requests
and other durations. Hence, JSF defines various levels of...
none (or "no scope")
request
session
application
...granularity. No (none ) granularity is when the bean has no scope, is
created on the fly and whenever needed. The request is the bean having
scope (and managed properties and values) only for the duration of an HTTP
request. By session , the bean properties and values remain in effect
(modified as many times or none) for an arbitrary length of time or operations
as conceived by the developer, for example, a shopping cart that dies after a
user has ordered or left the web site. Finally, the application -scoped
bean exists while the application is up and running, for example a database
connection.
Configuration support
The primary task of JSF is to present a web interface to a client that is
predictably and automatically synchronized with one or a set of managed objects
without extensive, spaghetti-like and difficult coding.
System properties
Much is configurable in Java and:
String property = System.getProperty( property-name );
...is how a property is got. There are three ways they are set.
First, Sun sets them, like java.io.tmpdir , predefined, in its JRE.
Other JREs do too and, from platform to platform, there is sometimes the
tiniest bit of non-conformance.
Second, you can set them yourself using the command line:
# java -Dhow.i.feel=blue MyClass
Last, you can set them programmatically:
String libraries = System.getProperty( "java.library.path" );
if( libraries != null && libraries.length() != 0 )
libraries += ":" + "/home/russ/dev/libs";
else
libraries = "/home/russ/dev/libs";
System.setProperty( "java.library.path", libraries );
File.createTempFile()
A temporary file is created in java.io.tmpdir :
File f = File.createTempFile( "fun", ".poo" );
System.out.println( "Just created file "
+ f.getName()
+ " in directory "
+ System.getProperty( "java.io.tmpdir" )
);
The ternary operator
The ternary operator in Java is problematic, having trouble with mixed,
ambiguous or unclear typing in places where humans do not.
In the example, a compile-time error is generated.
In order to force understanding on the compiler, use parentheses as shown in
the subsequent line. This forces evaluation of the expression before settling
on what type is its result.
Type mismatch: cannot convert from String to boolean.
Double x = 9.0;
System.out.println( "This is a " + ( x == 9.9 ) ? "test" : "cat" + " of the Emergency Broadcast System" );
/* fixed: */
System.out.println( "This is a " + ( ( x == 9.9 ) ? "test" : "cat" ) + " of the Emergency Broadcast System" );
Viewing the contents of a JAR
(A quicker way to do this is to follow
How to examine a JAR (or WAR) in Linux or to do this from the command line:
$ file-roller jar-name
)
Dump the particulars including class list for a JAR. If binary jar
isn't on $PATH , find it in the JDK under the bin subdirectory. The
options are mostly identical to tar :
russ@taliesin:~/dev/downloads/myfaces-core-1.2.8/lib> jar tvf myfaces-impl-1.2.8.jar
META-INF/
META-INF/MANIFEST.MF
META-INF/services/
javax/
javax/faces/
org/
org/apache/
org/apache/myfaces/
org/apache/myfaces/event/
org/apache/myfaces/taglib/
org/apache/myfaces/taglib/core/
org/apache/myfaces/taglib/html/
org/apache/myfaces/convert/
org/apache/myfaces/portlet/
.
.
.
META-INF/NOTICE.txt
META-INF/standard-faces-config.xml
META-INF/myfaces_core.tld
META-INF/myfaces_html.tld
META-INF/LICENSE.txt
META-INF/myfaces-metadata.xml
javax/faces/Messages_pl.properties
javax/faces/Messages_ru.properties
javax/faces/Messages_ja.properties
javax/faces/Messages_mt.properties
javax/faces/Messages_it.properties
javax/faces/Messages_ca.properties
javax/faces/Messages.properties
javax/faces/Messages_en.properties
.
.
.
org/apache/myfaces/taglib/core/ValidateDoubleRangeTag.class
org/apache/myfaces/taglib/core/SetPropertyActionListenerTag.class
org/apache/myfaces/taglib/core/LoadBundleTag.class
org/apache/myfaces/taglib/core/ConvertNumberTag.class
org/apache/myfaces/taglib/core/PhaseListenerTag$BindingPhaseListener.class
org/apache/myfaces/taglib/core/ValidatorImplTag.class
org/apache/myfaces/taglib/core/SubviewTag.class
org/apache/myfaces/taglib/core/GenericListenerTag.class
org/apache/myfaces/taglib/core/ConverterImplTag.class
org/apache/myfaces/taglib/core/LoadBundleTag$BundleMap.class
org/apache/myfaces/taglib/core/SelectItemTag.class
org/apache/myfaces/taglib/core/ActionListenerTag.class
org/apache/myfaces/taglib/core/GenericMinMaxValidatorTag.class
org/apache/myfaces/taglib/core/DelegateConverter.class
org/apache/myfaces/taglib/core/ConvertDateTimeTag.class
org/apache/myfaces/taglib/core/SelectItemsTag.class
org/apache/myfaces/taglib/core/VerbatimTag.class
.
.
.
org/apache/myfaces/webapp/StartupServletContextListener.class
.
.
.
org/apache/myfaces/application/jsp/ViewResponseWrapper$WrappedServletOutputStream.class
org/apache/myfaces/application/MyfacesStateManager.class
org/apache/myfaces/application/TreeStructureManager$TreeStructComponent.class
org/apache/myfaces/application/ApplicationFactoryImpl.class
org/apache/myfaces/application/DefaultViewHandlerSupport.class
org/apache/myfaces/application/ActionListenerImpl.class
META-INF/maven/
META-INF/maven/org.apache.myfaces.core/
META-INF/maven/org.apache.myfaces.core/myfaces-impl/
META-INF/maven/org.apache.myfaces.core/myfaces-impl/pom.xml
META-INF/maven/org.apache.myfaces.core/myfaces-impl/pom.properties
Runnable (stand-alone) JUnit testing
To run from the command line a JUnit test you've created, you need a
main() method to call it. Create your JUnit test class as
normal, here, FunTest , create another class with a
public static void main( String[] args )
inside that calls it
thus:
import junit.textui.TestRunner;
public class RunnableFunTest
{
public static void main( String[] args )
{
TestRunner.run( FunTest.class );
}
}
Obviously, when you run this from the command line, you'll also have to
make allowances for the JUnit JAR (library) to be present.
Enabling Java assertions...
Java assertions have nothing to do with JUnit. In order to enable them,
add -ea (or, -enableassertions ) to the
Java command line , to the launch configuration in Eclipse or as a
default VM argument in the installed JRE (Preferences -> Java ->
Installed JREs (select a JDK/JRE) Edit .
Encapsulation is...
...these three things, most importantly:
Separation of concerns, a phrase borrowed from Edger Djikstra, 1975.
"Let me try to explain to you, what to my taste is characteristic for all
intelligent thinking. It is, that one is willing to study in depth an aspect
of one's subject matter in isolation for the sake of its own consistency, all
the time knowing that one is occupying oneself only with one of the aspects.
We know that a program must be correct and we can study it from that viewpoint
only; we also know that it should be efficient and we can study its efficiency
on another day, so to speak. In another mood we may ask ourselves whether, and
if so: why, the program is desirable. But nothing is gained —on the contrary!—
by tackling these various aspects simultaneously. It is what I sometimes have
called "the separation of concerns", which, even if not perfectly possible, is
yet the only available technique for effective ordering of one's thoughts,
that I know of."
An object's information (data) is separate from its interfaces.
Information-hiding, a term borrowed from David Parnas, 1972.
"We have tried to demonstrate by these examples that it is almost always
incorrect to begin the decomposition of a system into modules on the basis of
a flowchart. We propose instead that one begins with a list of difficult
design decisions or design decisions which are likely to change. Each module
is then designed to hide such a decision from the others."
C.f. Java's private and, to a lesser extent, protected
modifiers.
Ripple effects, a term borrow from Wayne Stevens, 1974.
"The fewer and simpler the connections between modules, the easier it is to
understand each module without reference to other modules. Minimizing
connections between modules also minimises the paths along which changes and
errors can propagate into other parts of the system, thus eliminating
disastrous, 'Ripple effects,' where changes in one part causes errors in
another, necessitating additional changes elsewhere, giving rise to new
errors, etc."
I.e.: coupling and cohesion .
Problems with supposed encapsulation
Encapsulation is popularly implemented through usage of private attributes with
accessors. Using this method to achieve encapsulation when the attribute is a
java.util.Collection , java.util.Map , etc. is just plain wrong.
public class MyBean
{
private Collection collection;
public Collection getCollection() { return collection; }
public void setCollection( Collection collection ) { this.collection = collection; }
}
...or even eschewing the setter by using a constructor:
public class MyBean
{
private Collection collection;
public MyBean( Collection collection ) { this.collection = collection; }
public Collection getCollection() { return collection; }
}
...will not make the interior collection immutable since a handle to it on the
outside will make it modifiable. The following could be tried:
public class MyBean
{
private List collection = new ArrayList();
public MyBean( Collection collection ) { this.collection.addAll( collection ); }
public Collection getCollection() { return Collections.unmodifiableList( collection ); }
}
Tracking down memory leaks in Java
Here is an article:
Monitoring and Detecting Memory Leaks in Your Java Application .
Note that thread-local store use and web applications running in a container like
Tomcat can easily sport memory leaks that must be cogitated and analyzed.
Hunting memory leaks in production
Notes on overt thread safety in Java
I used to code in C and assembly on a multithreaded, multiprocessor operating
system (NetWare). I knew all the ins and outs.
Java, however, is not C and has different ways of doing things.
Here are the details on the Java synchronized keyword:
Synchronized code: This locks code down a little like a barrier
in C. (Well, okay, not much like that, but it's sort of the same idea.)
public synchronized method()
{
...
}
Synchronize code on a variable: actually, this is what's really
happening even in the case above because the variable there is
implicit. If execution encounters code attempting to synchronize
on the same object, then that object becomes, like a mutext,
contended .
Another, more intelligent way to support thread-safe execution in Java
includes, just as in other languages including C, to eliminate shared
data. If threads don't share objects, then it doesn't matter when
threads run or what they do to their data.
Replacing Java 6 with Java 7
This is in the context of running Tomcat. See
JAVA_HOME for Tomcat .
UnsupportedClassVersionError in Java
When you see a stack trace with...
java.lang.UnsupportedClassVersionError: SomeClass : Unsupported major.minor version 51.0 (unable to load class SomeClass )
.
.
.
...it probably means that you compiled your application with a Java compiler
of a more recent version than the JVM you're trying to run it on.
How to override equals() and hashCode() properly
Equivalence must define a relation that's reflexive, symmetric, transitive and
consistent. If null, what's being compared must return false . Apache
Commons has some great helps for this.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Poop
{
private String name;
private int age;
public boolean equals ( Object o )
{
if( o == null )
return false;
if( o == this )
return true;
if( !( o instanceof Poop ) )
return false;
Poop poop = ( Poop ) o;
return new EqualsBuilder()
.append( name, poop.name )
.append( age, poop.age )
.isEquals();
}
public int hashCode ()
{
return new HashCodeBuilder( 17, 31 ) // two randomly chosen prime numbers
.append( name )
.append( age )
.toHashCode();
}
}
Visual VM bundled with JDK
Web site: http://visualvm.java.net/ .
MBeans
Use to read and set properties with this plug-in directly in memory effectuating changes on the fly.
Launch thus from console:
$ jvisualvm
...and install Tools -> Plugins including:
VisualVM-MBeans
VisualGC
Threads Inspector
VisualVM-JConsole
If, when you click on the MBeans tab, you see:
Data not available because JMX connection to the JMX agent could not be
established.
This link sort of applies:
http://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote ,
but you only need some of it (if you're not debugging remotely).
In Run/Debug configuration, for VM options:
-Dcom.sun.management.jmxremote
Dependency injection (Inversion of control)
Better than Guice; Dagger for dependency injection:
http://square.github.io/dagger/ .
The history of identifier deprecation in Java
I was completely taken by surprise this morning.
These annotations have a rather sordid history including hopeless pleas now in
our day exhorting correct usage which, officially and numerously (see
stackoverflow.com * et al.) at least, is supposed to consist of employing
both annotations simultaneously.
From Oracle (Sun) docs (underlining mine):
NOTE: The Java Language Specification requires compilers to issue warnings when
classes, methods, or fields marked with the @Deprecated annotation are
used. Compilers are not required by the Java Language Specification to issue
warnings when classes, methods, or fields marked with the @deprecated
Javadoc tag are accessed, although the Sun compilers currently do so. However,
there is no guarantee that the Sun compiler will always issue such warnings.
Using the @Deprecated Annotation
J2SE 5.0 introduces a new language feature called annotations (also called
metadata). One of the Java language's built-in annotations is the
@Deprecated annotation. To use it, you simply precede the class, method, or
member declaration with "@Deprecated."
This next document demonstrates that the Javadoc-looking annotation
predates—to at least 1996. Note the statement,
This is the first time the compiler is in any way cognizant of document
comment contents. (Once, it made sure that they were at the right place in
the parse tree, but this is no longer true.) We did not lightly choose to
make the compiler's behavior dependent on the contents of a comment.
(Yeah, no kidding? They must have been desperate. C already long sported
#pragmas ; I'd have reached the conclusion to implement annotations
right then and there, Java 1.1, instead of awaiting Java 1.5.)
http://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/guide/misc/deprecated.html
*
http://stackoverflow.com/questions/9031832/how-to-declare-or-mark-a-java-method-as-deprecated
OS/system details in Java
http://java.dzone.com/articles/get-your-os-distribution
How I eliminated Oracle/Sun JDK
Not that I feel the need to do this. OpenJDK/JRE usually works fine and so does
the Sun JDK/JRE. At work, they were in a "let'd get rid of Oracle" mood and
while that's really only a database issue, it was proposed that the baby get
tossed out too. No matter. Here's how I did it; I'm running Mint (Ubuntu) these
days.
Please note that Oracle/Sun typically installs on the host at /opt/java ,
e.g.: /opt/java/jdk1.7.0_51 . It is not seen via dpkg --list nor
removed via apt-get purge/remove .
I'm dumbing this down a bit to reveal all the details that would otherwise have
to be guessed at.
If it's really a JDK (and not merely a JRE) and you've done everything right,
IntelliJ should start without the "missing tools.jar / please use a proper JDK
message".
Install openjdk 7, the one you want.
~ $ sudo bash
~ # apt-get update
~ # apt-get install openjdk-7-jdk
Fix up links in /usr/lib/jvm :
/usr/lib/jvm # ll
total 56
drwxr-xr-x 4 root root 4096 Jun 25 12:52 .
drwxr-xr-x 203 root root 36864 Jun 25 12:52 ..
lrwxrwxrwx 1 root root 18 Mar 13 2012 java-1.5.0-gcj -> java-1.5.0-gcj-4.6
drwxr-xr-x 6 root root 4096 Feb 7 14:03 java-1.5.0-gcj-4.6
lrwxrwxrwx 1 root root 20 Apr 25 12:31 java-1.7.0-openjdk-amd64 -> java-7-openjdk-amd64
-rw-r--r-- 1 root root 2439 Apr 25 12:31 .java-1.7.0-openjdk-amd64.jinfo
drwxr-xr-x 5 root root 4096 Jun 25 10:56 java-7-openjdk-amd64
lrwxrwxrwx 1 root root 12 Mar 13 2012 java-gcj -> java-gcj-4.6
lrwxrwxrwx 1 root root 18 Apr 16 2012 java-gcj-4.6 -> java-1.5.0-gcj-4.6
-rw-r--r-- 1 root root 946 Apr 16 2012 .java-gcj-4.6.jinfo
I added this link.
lrwxrwxrwx 1 root root 26 Jun 25 13:06 java-7 -> ./java-1.7.0-openjdk-amd64
Fix up /etc/alternatives .
/etc/alternatives # ll java
lrwxrwxrwx 1 root root 30 Feb 7 14:05 java -> /opt/java/jdk1.7.0_51/bin/java
which I changed to:
/etc/alternatives # ll java*
lrwxrwxrwx 1 root root 30 Feb 7 14:05 java.old -> /opt/java/jdk1.7.0_51/bin/java
lrwxrwxrwx 1 root root 28 Jun 25 13:08 java -> /usr/lib/jvm/java-7/bin/java
I can remove java.old once everything is working.
Fix up your .profile , something like:
export JAVA7_HOME=/usr/lib/jvm/java-7-openjdk-amd647
export JAVA_HOME=${JAVA7_HOME}
export IDEA_JDK=${JAVA7_HOME}
export M2_HOME=/home/russ/dev/apache-maven-3.1.1
export M2=${M2_HOME}/bin
export MAVEN_OPTS="-Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512"
PATH=/home/russ/bin:${JAVA_HOME}/bin:${PATH}
PATH=${PATH}:${M2}
so that your path appears thus:
~ $ echo $PATH
/home/russ/bin:/usr/lib/jvm/java-7/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:\
/sbin:/bin:/home/russ/dev/apache-maven-3.1.1/bin
~ $ which java
/usr/lib/jvm/java-7/bin/java
~ $ java -version
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1ubuntu1~0.12.04.2)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
The Java @Override snafu
The first things to remember are that Java 5 introduced...
Annotations, including @Override .
Interfaces, which had not existed before (everyone use abstract ).
In Java 5, @Override was introduced for use in overriding a method
from a superclass (including abstract classes). It was not offered for
use on methods implementing a method from an interface .
In Java 7, @Override is tolerated for methods of a class that
implement methods listed in an interface . However, it is not
necessary. This is why you don't get errors for either method below:
public interface Foo
{
public void fooit();
public void barit();
}
public class Bar implements Foo
{
@Override
public void fooit() { }
public void barit() { }
}
Nevertheless, when compiling with Java 6, you do get an error for the
implementation of fooit().
I personally think it makes more sense not to use @Override when
implementing an interface 's contractual methods, but it's only a
problem when you maintain code compiled sometimes by JDK 5/6 and sometimes by
JDK 7/8.
Swiss Java knife
A useful, open-source tool to add to Java diagnostic toolkit.
Swiss Java Knife offers a number of commands:
jps - Similar to the jps tool that comes with the JDK.
ttop - Similar to the linux top command.
hh - Similar to running the jmap tool that comes with
the JDK with the -histo option.
gc - Reports information about garbage collection in real time.
mx - Allows you to do basic operations with MBeans from the
command line.
mxdump - Dumps all MBeans of the target java process to JSON.
Links:
Java thread safety
How JEE applications execute
Applications start with one master thread, the main thread, which hangs
around keeping the application alive. This is usually part of the
container in Java EE.
On receiving user input or on receiving a request from client, the master
thread may start new thread(s) to get the work done. Some entry method is
called on your managed component - like doGet() or
doPost() or a bean's business method.
From this point onward you are not creating any further threads, so you
are coding with a single thread in mind.
As your code executes, you may create objects with new and work with them.
You may share few of these objects with the container or hold static
reference to the objects. These can become accessible to other threads.
Your code can also access container-provided objects, singletons (and
other objects held in static references), etc. which may be created by other
threads and are visible to you.
How visibly to show code is safe
Write minimal amounts of code in static methods—implement business
logic as instance methods not static methods. Even if you write static
methods, avoid static instance variables (just do some work, don't store
anything).
Don't expose: Keep as many objects unshared as possible. For example, don't
write getters and setters for internal variables.
Use lots of new and don't unnecessarily reuse. For example, don't reuse a
SimpleDateFormat . Just create one each time you need to format or
parse a date (or keep it as a private instance variable and mark it final.
But don't make it static. Once you make it static it can be accessed by
multiple threads).
Similarly, create new ArrayList s and StringBuilder s
freely, don't reuse. (Code reuse is good, object reuse is bad)
Create new instances every time for custom objects also. For example,
create new BO and DAO objects. Use the objects the throw them (let them get
garbage collected). Don't try to reuse.
For extra safety, make task-oriented objects like BO/Bean and DAO stateless
as far as possible (by avoiding instance variables).
Make shared objects read-only (immutable) as far as possible: For example,
if you have a list of countries supported by your application, that list is
not going to change. So, mark the reference as final and use immutable
lists/maps (See:
http://stackoverflow.com/questions/7713274/java-immutable-collections ).
Java collections
The Java collection consists of Set s, List s and
Queue s:
Lists
Lists can contain duplicates, even LinkedList . If you want to
eliminate duplicates (automatically), use a Set -type. What's different
between types of lists is the speed of certain operations and this is how to
pick which one to use in a given situation.
ArrayList - dynamically sizing array. Fast random-read access,
get() takes constant time. Adding and removing require shifting of the
array elements in memory, however. When the size of the array must be increased
due to addition, a new array of size 150% is allocated and the old array must
be copied. The default, unspecified size (Java 4 through 7) is 10. Constructing
it with more saves time if you know there will be more.
ArrayList is hugely expensive for remove operations and for add
operations when the size allocated is used up.
Vector works like ArrayList , but is synchronized and
therefore thread-safe—and slightly slower. Most programmers eschew this
in favor of ArrayList since they want to synchronize explicitly
anyway.
LinkedList - doubly linked list. Best for constant-time
insertions and sequential access of elements. Finding a position in the array
takes time proportional to the length of the list. The size penalty for the
overhead grows considerably over that for ArrayList at, on a graph,
almost a 45° angle. (Note: since late Java 6, no distinction between 32-bit
and 64-bit is distinguishable—64-bit used to have even more overhead.)
—better for add and remove than ArrayList , worse for get and set
operations. Use LinkedList if there are going to be few random accesses
(get() , contains() ) or many add or remove operations.
See
http://www.programcreek.com/2013/03/arraylist-vs-linkedlist-vs-vector/ .
HashMap is like an ArrayList of key-value pairs, but
it is not implemented within the framework of Java collections (it's not a set,
list or queue). It is a Map . Keys in a map cannot occur in duplicates.
Sets
In a set, no duplicates are allowed. When adding, duplicates are removed
automatically. The three most commonly used sets implementations are
HashSet (fast), LinkedHashSet (order-preserving) and
TreeSet (maintained sorted, slowest).
EnumSet - alternative to bit fields in C, for iteration over a set of flags.
HashSet - elements are unordered, held in a hash table. Good performance. Add,
remove and contain operations have constant-time complexity.
LinkedHashSet - is a sort of hash table with a linked list running through it,
maintaining the order of insertion, but not reordering new insertions respective to
existing ones. Performance compromise between the above.
See
http://www.programcreek.com/2013/03/hashset-vs-treeset-vs-linkedhashset/ .
Queues
(Not today.)
Java maps
The Java map consists of HashMap , LinkedHashMap ,
TreeMap and Hashtable .
HashMap - makes no guarantee as to order, allows one null key and
null values. Traversed using iteratory, entry set. (Inherits AbstractMap .)
LinkedHashMap - preserves the original insertion order, but is
otherwise identical to HashMap .
TreeMap - uses natural or comparator-based ordering to maintain
contents in-order. Null keys only allowed if comparator used and doesn't thrown
an exception.
Hashtable - makes no guarantee as to order, disallows null keys
and values, is synchronized and therefore expensive if you don't need that.
Traversed using enumerator and iterator. (Inherits Dictionary .)
Java filepaths
You try to create a file. Where is it? Original, Windows code:
File child = new File(".././Java.txt");
getPath() —likely relative to current working subdirectory.
..\.\Java.txt
getAbsolutePath() —fully qualified path, but in
relationship to the current working subdirectory.
C:\Users\WINDOWS 8\workspace\Demo\..\.\Java.txt
getCanonicalPath() —full path from the filesystem's point
of view.
C:\Users\WINDOWS 8\workspace\Java.txt
Converting String to InputStream
See here .
byte[] to String
byte[] aByte = new String( ".976" ).getBytes();
String propertyValue = new String( aByte );
...otherwise, aByte.toString() yields gobble-dee-gook.
Exceptions
... exist in checked and unchecked varieties. The original idea:
Unchecked exceptions represent defects in the application code, perhaps a null
pointer, an invalid argument passed to a non-private method. These represent
conditions that, generally speaking, reflect errors in logic and cannot be
reasonably recovered from at runtime.
At least that was the theory in the 1990s.
Checked exceptions are invalid conditions in area outside immediate control of
application code including invalid user input, database problems, network
outages, absent files, etc.
They are subclasses of Exception.
Methods are obliged to establish a policy for all checked exceptions thrown by
its implementation (either by passing the problem further up the stack or
throwing again to be handled elsewhere).
If a client can reasonably be expected to recover from an exception, make it a
checked one. If unreasonable, make it unchecked. Avoid unnecessary use of
checked exceptions which place a burden on the programmer.
Exceptions, version 2
Any exception that can be thrown by a method is part of the method's
public programming interface.
Methods calling such a method must know about the exceptions that the
latter can throw and decide what to do about them.
Runtime exceptions represent (only) problems that are the result of a
programming solutions from which the calling method cannot be reasonably
expected to recover or handle in any graceful or useful way. This would
include dividing by zero, null-pointer references and indexing exceptions
(attempting to access a list or array with an index outside the existing
bounds of the data). Illegal arguments are also reasons to throw
RuntimeException . Forcing code to check such exceptions reduces
the clarity of the code.
Moral of the story: If code cannot reasonably or usefully recover from an
exception, then leave it as an unchecked exception. Otherwise, make it a
checked exception.
┌───────────┐
│ Throwable │
└───────────┘
/ \
/ \
┌───────┐ ┌───────────┐
│ Error │ │ Exception │
└───────┘ └───────────┘
/ | \ / | \
\_______/ \______/ \
┌──────────────────┐
unchecked checked │ RuntimeException │
└──────────────────┘
/ | | \
\_________________/
unchecked
Java API exceptions
This is API theory: the right/best way to do things.
Returning null
This means the intent of the code is not explicit without looking at the
JavaDocs, and so the worst option on our list.
Returning an Optional< T >
This makes the intent explicit compared to returning null. Of course, this
requires Java 8.
Return a Guava's Optional< T >
For those of us who are not fortunate enough to have Java 8.
Returning one's own Optional< T >
If you don't use Guava and prefer to embed your own copy of the class instead
of relying on an external library.
Returning a Try
Cook up something like Scala's Try, which wraps either (hence its old
name, "Either") the returned bean or an exception. In this case, however, the
exception is not thrown but used like any other object, hence there will be no
performance problem.
Conclusion: when designing an API, one should really keep using exceptions for
exceptional situations only.
A better piece of advice (not mine, but a quote I read somewhere):
"When designing an API, I use the "get vs. find rule." The API's user needs to
know how to handle the absence of a result. A get is expected to always return
a result while a find is not. And so when coding getX() it returns the
result or throws an exception—such as
llegalStateException —if there is not one. Where as, when coding
findX() it returns a result if available or a null, or an empty
collection, if there is not one."
Checked/unchecked exceptions
1. Throwable and Error classes should not be caught
Throwable is the superclass of all errors and exceptions in Java. Error is the
superclass of all errors which are not meant to be caught by applications. Thus, catching
Throwable would essentially mean that Error s such as system exceptions (e.g.,
OutOfMemoryError , StackOverFlowError or InternalError ) would also get
caught. The recommended approach is that an application should not try to recover from errors such
as these. Therefore, Throwable and Error classes should not be caught. Only
Exception and its subclasses should be caught.
Data errors such as encoding issues etc which are not known at programming time should be caught
using this technique. However, catching Throwable such as InternalError or
OutofMemoryError would not be of any help and should never be thrown.
Avoid writing code consisting of catching Throwable as general practice.
2. Throwable.printStackTrace(...) should never be called
One should avoid invoking printStackTrace() method on
Throwable /Exception classes and instead use a logging framework.
3. Generic exceptions Error , RuntimeException ,
Throwable and Exception should never be thrown
The primary reason to avoid throwing generic Exceptions , Throwable and
Error is that doing so prevents classes from catching the intended exceptions. A caller
cannot examine the exception to determine why it was thrown and consequently cannot attempt
recovery.
Catching RuntimeException is considered a bad practice. Throwing generic
Exceptions /Throwable leads the developer to catch the exception at a later stage
which usually leads to worse practices.
Do not throw a generic exception like RuntimeException . Do, however, throw a custom-rolled
exception that inherits from RuntimeException .
4. Exception handlers should preserve the original exception
5. System.out or System.err should not be used to log exceptions
The primary reason one should avoid using System.out or System.err to log
exceptions is that one might simply loose the important error message.
Checked exceptions!
One man's opinion...
It is an utterly failed experiment because it is designed around the totally
flawed assumption that the service/library throwing the exception should decide
which ones should be checked and which ones should not. In reality, only the
caller knows which ones should be caught (usually none), and which ones should
not.
6. Generally, whenever a library-method is called that throws a checked
exception, just do:
try
{
libraryObject.method();
}
catch( Exception e )
{
throw new MyAppRuntimeException( e );
}
...to prevent this checked-exception idiocy from propagating like a virus and
infecting the whole application.
Don't throw an instance of class Exception ...
Throwing java.lang.Exception is bad practice...
Exception thrown explicitly by your code becomes impossible to
discriminate from among other (unexpected) exceptions in a catch clause.
Better by far to pick a more specific exception, including manufacturing a
proprietary one if there's nothing obviously suitable.
Reasons for resorting to a conditional...
...to think about and perhaps solve. Some are unavoidable—foisted upon one
by someone else, some are code stench.
Checking a value returned to me from code I own (null-pointer check stench)?
Checking a value returned to me from code I do not own?
Checking a parameter passed to me by code I own (control couple stench)?
Checking a parameter passed to me by code I do not own?
Checking my own state or attributes?
Checking a value I set previously in this method?
Checking the type of an exception thrown by code I own?
Checking the type of an exception thrown by code I do not own?
How to close streams for sure
This code doesn't close streams although it's trying. It could throw an
exception when one fails to close. If attempting to close fis fails,
the code throws an exception and prints out a warning, but nothing is done to
attempt to close fos .
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
fis = new FileInputStream( "stuff-to-read.txt" );
fos = new FileOutputStream( "stuff-put-out.txt" );
...
}
finally
{
try
{
if( fis != null )
fis.close();
if( fos != null )
fos.close();
}
catch( IOException e )
{
System.out.println( "Failed to close streams" );
}
}
This code will do the trick, but it's a bit unsightly. It takes up a lot
of space and obfuscates a simple thing.
InputStream fis = null;
OutputStream fos = null;
try
{
fis = new FileInputStream( "stuff-to-read.txt" );
fos = new FileOutputStream( "stuff-put-out.txt" );
...
}
finally
{
try
{
if( fis != null )
fis.close();
}
catch( IOException e )
{
;
}
try
{
if( fos != null )
fos.close();
}
catch( IOException e )
{
;
}
}
JVM mind (share) map
Click to see full size.
Random in Java
Check out these claims when you get a chance.
import java.lang.reflect.Field;
import java.util.Random;
public class Entropy
{
public static void main(String[] args) throws Exception
{
// extract the IntegerCache through reflection...
Class< ? > clazz = Class.forName( "java.lang.Integer$IntegerCache");
Field field = clazz.getDeclaredField("cache");
field.setAccessible( true );
Integer[] cache = ( Integer[] ) field.get( clazz );
// rewrite the Integer cache...
for( int i = 0; i < cache.length; i++ )
cache[ i ] = new Integer( new Random().nextInt( cache.length ) );
// prove randomness...
for( int i = 0; i < 10; i++ )
System.out.println( ( Integer ) i );
}
}
Reverse string
public class StringReverse
{
private static final String[] FODDER =
{ // palindromes except the first...
"Off to the races...",
"Madam I'm Adam",
"A dog, a plan, a canal: pagoda",
"A nut for a jar of tuna",
"A Santa at NASA",
"A slut nixes sex in Tulsa",
"A car, a man, a maraca"
};
private static String reverse( String string )
{
if( string.length() < 2 )
return string;
/* Algorithm: Grab everything after the first character and return
* it followed by the (soon to be former) first character itself.
*/
return reverse( string.substring( 1 ) ) + string.charAt( 0 );
}
public static void main( String[] args )
{
for( String string : FODDER )
{
String message = "String " + string + " ";
int TAB = 40, length = message.length();
System.out.print( message );
while( length++ < TAB )
System.out.print( " " );
System.out.println( " reversed is: " + reverse( string ) );
}
}
}
Output:
String Madam I'm Adam reversed is: madA m'I madaM
String Off to the races... reversed is: ...secar eht ot ffO
String A dog, a plan, a canal: pagoda reversed is: adogap :lanac a ,nalp a ,god A
String A nut for a jar of tuna reversed is: anut fo raj a rof tun A
String A Santa at NASA reversed is: ASAN ta atnaS A
String A slut nixes sex in Tulsa reversed is: asluT ni xes sexin tuls A
String A car, a man, a maraca reversed is: acaram a ,nam a ,rac A
Arrays.toString() minus the brackets
Arrays.toString( array ) surrounds the whole with "[ ... ]"—not
what we want.
private String arrayToString( String[] array )
{
StringBuilder sb = new StringBuilder();
boolean first = true;
for( String particle : array )
{
if( !first )
sb.append( ' ' );
sb.append( particle );
first = false;
}
return sb.toString();
}
EarlyExitException is not EarlyExitException (symbol is not symbol)
Beware (duh!) that if you have a duplicate class, EarlyExitException ,
in your code and are building using a JAR that also has that symbol, uses and
throws it, your code will not be catching it just because you happen also to
have EarlyExitException . They are different and you get errors like
unreported exception EarlyExitException; must be caught or declared to be thrown
because EarlyExitException is not EarlyExitException .
Unsupported major.minor version 52.0
This happens when you've got code in your JAR, WAR or NAR compiled with a
higher version of Java (in my case 8) for a higher version of Java (in
my case, 8 though I wasn't specifying it by using this plug-in).
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
The solution is to build everything with 1.7 (or whatever). Use Maven to clean
out what's there before recompiling and packaging with this plug-on
configuration in place.
Notes on Java serialization
public class SerializableClass implements Serializable
{
private static final long serialVersionUID = 456778567857L;
public String firstField = "First Field";
public transient static String secondField = "Second Field";
public transient final String thirdField; // unintialized
public transient final String fourthField = "Fourth Field";
private int privateField = 99;
Notes
serialVersionUID is explicitly defined to prevent
InvalidClassException during deserialization. As the default
serialVersionUID computation is highly sensitive to class
details that may vary depending on compiler implementations and can
produce different results in different environments, beware.
firstField will be serialized, and the default value can be
overridden in subsequent classes that are serializing
SerializableClass.java .
secondField , thirdField and fourthField , being
either transient static or transient final , will never
be serialized. The values these will have will be restored at
deserialization from whatever their values are in SerializableClass
at the time it happens.
privateField is private. It will be serialized, but can be read
only through reflection.
Notes on JVM heap memory
Java thinks in terms of ordinary object pointers (OOPs) rather than native
machine pointers (64-bit addresses in our day). These managed "pointers" are
created such that the JVM can address up to 4-billion objects (not bytes, but
full objects of arbitrary size). This is done via a phenomenon called
compressed OOPs . See
Java HotSpot™ Virtual Machine Performance Enhancements .
See also
Java Performance Tuning Guide .
The up-shot of this is that the JVM uses only 4-byte references (remember, these are
not memory pointers). This means that there is a huge savings on 64-bit machines in
terms of "pointer overhead." However, in this "express mode," you effectively only
benefit from a -Xmx31Gb heap (though there's a huge savings in terms of
what you think are pointers throughout your data: you save 4 bytes for each "memory"
reference in your Java data objects).
In reality, the actual heap setting is something like -Xmx32Gb-1Mb
because the consequence of graduating from OOPs to (64-bit) object references
begins at about 1Mb before 32Gb.
64-bit (byte) addressing
Once your heap exceeds 32Gb nominally, you're in full, 64-bit land and your references
begin to use 64-bits of reference (instead of the express OOP solution). Setting your
heap somewhere between -Xmx32G - 1Mb and -Xmx38Gb will in effect
reduce the amount of heap space because you've now lost space to the 8-byte (instead
of 4-byte) memory references.
The JVM can manage about as much memory as you can throw at it, but it's much more
efficient at doing it below 32Gb. There's a lost space between 32Gb-1Mb and almost
38Gb in which you get less heap than if using 31Gb (or 32Gb-1Mb). Beyond 38Gb, you're
running in free and open territory because using 64-bit object references.
There's a non-zero effect upon garbage collection too. (Use -XX:+PrintGCDetails
to see this impact.) Not having direct experience with this, I'll abstain for now
from speculating on it.
Finally, it is not true that Java can't use more than 32Gb of memory . It's only
that it uses it differently and that there is a lost grey area before 38Gb (depends on
an application's peculiar object sizes just how wide this inefficiency actually is).
Notes on JVM garbage collection
These are the causes of the JVM garbage collection firing according to
frequency in an average application.
Allocation Failure
Application tried to make a new allocation and failed due to lack of
available space in Young generation; hence Minor GC is required.
On Linux, the JVM can trigger a GC if the kernel notifies there isn't much
memory left via mem_notify .
GC Locker
GC is started after all threads leave the JNI Critical region. For more
information on JNI, refer to the Java Native Interface documentation
website. GC is blocked when any thread is in the JNI Critical region and
can start only when all of them outside of it.
G1 Evacuation Pause
This is actual only for the G1 collector. It indicates that it is copying
live objects from one set of regions (Young and sometimes
Young + Tenured , which is called Mixed ) to another set
of regions.
G1 Humongous Allocation
This is actual only for the G1 collector. Humongous is an allocation when
its size is greater than 50% of one region size; the object then
allocated in special space. Nevertheless, it also causes normal GC
collection to get more (possibly continuous also) space for such objects.
CMS Initial Mark
Initial mark phase of CMS, for more details, see Phases of CMS. It also
triggers Young Space collection.
System.gc()
There was a System.gc() call in the application code. You can
start JVM with the -XX:+DisableExplicitGC flag to disable such
behavior.
Adaptive Size Ergonomics
Indicates you are using the adaptive heap size policy (ability to change
Young and Tenured spaces size at runtime), enabled via the
-XX:+UseAdaptiveSizePolicy flag. By default, it is enabled in
the recent versions of JVM.
Allocation Profiler
This is actual only for versions of Java before 8 and only when
-Xaprof
is set. It triggers just before JVM exits.
Heap Inspection
GC was triggered by an inspection operation on the heap, most probably by
the jmap tool with the -histo:live flag set.
Heap Dump
GC was initiated before heap dump is made by some profiling instrument.
No GC
Normally, you shouldn't see this reason. It was occurring in older Java
versions, in case jstat command was started before any collection
occurred. Other case is when jstat checks GC without any GC activity.
Last-ditch Collection
When Metaspace (Java 8+) or PermGen (Java 7-) is full and you can't
allocate a new object here, JVM first tries to clean it, triggering
appropriate collector. If that's not possible, it then tries to expand
it. If that doesn't work as well, it triggers Full GC with this cause
name. Soft references are being cleaned during it as well.
Perm Generation Full
Triggered as a result of an allocation failure in PermGen. Actual for
Java versions prior to 8.
Metadata GC Threshold
Triggered as a result of an allocation failure in Metaspace. Metaspace is
a replacement for PermGen in Java 8+.
JvmtiEnv ForceGarbageCollection
Something called the JVM tool interface function ForceGarbageCollection.
Notes on immutable classes
An immutable class is simply one whose objects, once they've been instantiated,
are unmodifiable, i.e.: cannot be changed.
These include String , most implementations of date and time classes
and wrapper classes (c'est-à-dire Boolean , Short ,
Long , Double , Float . There are other examples such as
File . Classes following the Singleton pattern are typically
immutable. Enumerations are typically immutable (unless they've been badly
coded).
Benefits of immutable classes:
as noted, the object never changes
their methods are thread-safe
Steps to creating an immutable class:
Make all instance variables/fields private for no direct access.
Initialize only using constructors.
Make all instance variables/field final so they can't be changed
without failing compilation.
If providing for cloning, make it a deep-clone , that is, one that
does not copy object references including
the object itsef
any object internal to the object
Provide no setter methods.
Provide no getter method that fails to deep-clone the object
it returns.
Define the class as final in order that it not be extendable.
Matching groups in regular expressions in Java
public void funWithRegularExpressions( final String patient_local_id )
{
// 'patient_local_id' contains "Mercy_Hospital:665892"
String facilityName, separator, facilityId;
Pattern pattern;
Matcher matcher;
pattern = Pattern.compile( "^([\\w\\s]+)\\W.+$" );
matcher = pattern.matcher( patient_local_id );
facilityName = ( matcher.find() ) ? matcher.group( 1 ) : patient_local_id;
pattern = Pattern.compile( "^[\\w\\s]+(\\W).+$" );
matcher = pattern.matcher( patient_local_id );
separator = ( matcher.find() ) ? matcher.group( 1 ) : patient_local_id;
pattern = Pattern.compile( "^[\\w\\s]+\\W(.+)$" );
matcher = pattern.matcher( patient_local_id );
facilityId = ( matcher.find() ) ? matcher.group( 1 ) : patient_local_id;
System.out.println( "Facility name: " + facilityName );
System.out.println( " Separator: " + separator );
System.out.println( " Facility id: " + facilityId );
}
Output:
Facility name: Mercy_Hospital
Separator: :
Facility id: 665892
Strange string arithmetic...
In a twist right out of Paul Simon's, When Numbers Get Serious (read
second verse), I just encountered this weirdness today. I guess I don't do
stuff like this very often, but I was surprised to see it and I struggled
to find wording in Google to find its explanation:
1. int x = 1;
2. System.out.println( "x = " + x );
3. System.out.println( "x+1 = " + x+1 );
Output is:
x = 1
x+1 = 11
Freaky. I was doing this in some code I wrote.
So, what's going on? On line 3, the + operator is string
concatenation rather than arithmetic addition. Operator precedence assures
that x 's value is converted to a string, concatenated
"x+1 = " , then the value 1 is converted to a string and
concatenated to the previous string.
Consuming UNIX .so files from a project...
Ordinarily, one consumes a .so on the path indicated by
LD_LIBRARY_PATH . However, this isn't necessarily set to anything
especially when running or debugging in Eclipse, IntelliJ IDEA, etc.
Here's something I tried with success for consuming
libsigar-amd64-linux.so :
Copy the shared object to project-folder src/main/resources .
Edit run/debug configurations and add an environment variable:
LD_LIBRARY_PATH=/home/russ/dev/cassandra/target/classes
This works because, when built, the target subdirectory contains a
classes subdirectory to where, in addition to compiled Java class
files, anything put into the src/main/resources subdirectory gets
copied.
This solution is a bit volatile, however, in that you must maintain this
configuration when you run. Run/Debug Configurations in IntelliJ are
notoriously volatile. Also, this does nothing for the final Java product
JAR and you'll have to copy the shared object to wherever LD_LIBRARY_PATH
points before launching your Java application.
I've dealt with this before, but in specific environments and always tentatively.
Surely there's something better and more correct to say.
Handling exceptions in Java—best practices...
See
this article . The main points, however, are:
Clean up resources in a finally block
File file = new File( <pathname> );
try
{
FileInputStream inputStream = new FileInputStream( file );
// do something with inputStream...
}
catch( Exception e )
{
// handle exception...
}
finally
{
inputStream.close();
}
or use a (Java 1.7) try-with-resource statement,
which will automatically close the resources listed (assuming
they implement AutoCloseable :
File file = new File( <pathname> );
try ( FileInputStream inputStream = new FileInputStream( file ); )
{
// read the file...
}
catch( FileNotFoundException e )
{
// handle FileNotFoundException...
}
catch( IOException e )
{
// handle IOException...
}
Prefer specific (custom) exceptions in your application.
Document the exception the method specifies in its signature by means
of @throws in the Javadoc.
Throw exceptions with descriptive messages, e.g.:
throw new Exception( "This is a useful descriptive message for developers and users!" );
Catch the most specific exception first. Most IDEs enforce this by
noting "unreachable code."
Don't catch Throwable . This catches errors too that the JVM
intends that the application not handle (because they cannot be handled).
Don't ignore exceptions. IntelliJ stops bugging you about this if you
define catch( Exception ignored ) . This isn't good practice.
Don't log then rethrow; this writes multiple messages for the same
exception. If additional information needed, wrap in a custom
exception, then rethrow.
Wrap the exception caught and consume it, if by wrapping it in a
custom exception (especially standard ones).
SQL timestamp for "now"...
This tutorial on Date , Time and Timestamp is
elucidating:
https://alvinalexander.com/java/java-timestamp-example-current-time-now
Updating the installed Java
Building at home, I get:
russ@gondolin ~/sandboxes/cassandra-ps-index.clustering_feature.dev/code/cassandra-ps-index $ mvn package
.
.
.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project cassandra-ss-index-plugin: Compilation failure
[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
[ERROR] -> [Help 1]
This is because I have a JRE instead of a JDK, which is what happens by default
on a new Linux installation, which is what I have (Linux Mint 18.2 Sonya) since
my box sort of exploded a few weeks back. This will fix it, although the
alternatives thing never reveals to my satisfaction that I've fixed it:
russ@gondolin ~ $ sudo update-alternatives --config java
There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
Nothing to configure.
russ@gondolin ~ $ sudo apt-get install openjdk-8-jdk
russ@gondolin ~ $ sudo update-alternatives --config java
There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
Nothing to configure.
Yeah, looks the same to me. The only way I could tell that things were going to
work was:
russ@gondolin ~ $ cd /usr/lib/jvm/java-8-openjdk-amd64/
russ@gondolin /usr/lib/jvm/java-8-openjdk-amd64 $ ll
total 28
drwxr-xr-x 7 root root 4096 Nov 14 08:34 .
drwxr-xr-x 3 root root 4096 Nov 8 06:28 ..
lrwxrwxrwx 1 root root 22 Oct 27 16:51 ASSEMBLY_EXCEPTION -> jre/ASSEMBLY_EXCEPTION
drwxr-xr-x 2 root root 4096 Nov 14 08:34 bin
lrwxrwxrwx 1 root root 41 Jul 27 20:31 docs -> ../../../share/doc/openjdk-8-jre-headless
drwxr-xr-x 3 root root 4096 Nov 14 08:34 include
drwxr-xr-x 5 root root 4096 Nov 8 06:28 jre # not comforting...
drwxr-xr-x 3 root root 4096 Nov 14 08:34 lib
drwxr-xr-x 4 root root 4096 Oct 25 19:41 man
lrwxrwxrwx 1 root root 22 Oct 27 16:51 THIRD_PARTY_README -> jre/THIRD_PARTY_README
russ@gondolin /usr/lib/jvm/java-8-openjdk-amd64 $ find . -name '*tools*'
./lib/tools.jar # ah, now we know...
russ@gondolin ~/sandboxes/cassandra-ps-index.clustering_feature.dev/code/cassandra-ps-index $ mvn package
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.778 s
[INFO] Finished at: 2017-11-14T08:44:19-07:00
[INFO] Final Memory: 43M/357M
[INFO] ------------------------------------------------------------------------
Custom exceptions best practice
Always provide a benefit, though this might be slim, like funneling
everything through a common point.
Following the naming convention of ending the class name by -Exception .
Furnish JavaDoc that explains it all (see below).
Furnish a constructor that includes the exception's cause.
/**
* This exception wraps all checked exceptions and enriches them
* with a custom error code. You can use this code to retrieve
* localized error messages and to link to our online documentation.
*/
public class MyBusinessException extends Exception
{
public void wrapException( String input ) throws MyBusinessException
{
try
{
// do something
}
catch( NumberFormatException e )
{
throw new MyBusinessException( "A message that describes the error.",
e,
ErrorCode.INVALID_PORT_CONFIGURATION );
}
}
}
HttpURLConnection "keep alive"...
...and some comparison to OkHttpClient .
The problem is, should I attempt to write my own pool of HTTP connections to
improve performance when consuming the JDK's own HttpURLConnection ?
Other questions to answer include:
Is OkHttpClient superior to HttpURLConnection ?
Does it behoove me to provide a pool for HttpURLConnection or
OkHttpClient ?
Notes
OkHttpClient
While Android users have abandoned HttpURLConnection for OkHttpClient ,
and also some non-Android users too, this package does not appear on the face of my own
experience to improve performance despite claims that it offers its own connection pooling.
What OkHttpClient clearly offers that is superior to HttpURLConnection is
the cleaner, more easily understood interface and easier readability of a modern library.
It's always simpler to write a decent interface when you have so many older and poorer ones
to compare to.
Conclusion
It appears that HttpURLConnection offers pooling in its underlying socket
implementation because of this, there really isn't any way to intervene in that
implementation since you don't instantiate it, to wit, multiple instances of it. It's
impossible to do that. It appears, similarly, that OkHttpClient is the same.
The last article above makes the observation that, while it's possible to increase the
number of connections to keep alive, 10, 20 or 50 produce no visible improvement in the
number of out-going requests. It also observes that switching to the Apache HTTP client,
whose interface is notoriously changed every release (and you have to recode), the number of
out-going requests increased threefold with no fine-tuning.
The Apache HTTP client, like OkHttpClient also has a better API than the original
JDK client.
Finally, the last article, which is the most lucid and intact collection of observations
than any of the others, urges one not to call HttpURLConnection.disconnect() ,
increase the number of connections in the pool and drain both the input- and error streams.
ThreadPoolExecutor ...
The thread pool contained inside the ThreadPoolExecutor can contain
any number of threads. The number of threads in the pool is determined by
variables establish at construction:
corePoolSize and maxPoolSize .
If fewer than corePoolSize threads are created in the the
thread pool when a task is delegated to the pool, then a new thread
is created, even if idle threads exist in the pool.
If the internal queue of tasks is full, and corePoolSize
threads or more are running, but fewer than maxPoolSize
threads are running, then a new thread is created to execute the task.
Once the number of threads reaches maxPoolSize , and all threads
are busy when a new task is submitted, if a handler is registered, then
that task is rejected and, the handler takes over.
See RejectedExecutionHandler .
For RejectedExecutionHandler , this can be a very bad idea
because it's prone to dead-lock since all the threads in the pool may
have died before what you put into the queue is visible. This can be
mitigated using a keep-alive delay.
UnsupportedOperationException when adding one list to another
This just bit me (after years writing in Java). It took me some serious head-scratching
and Googling to figure it out. The secret is recounted in verbiage only if you understand
"Returns a fixed-size list backed by the specified array." That doesn't really jump out
at me, but there it is.
List< String > list1 = Arrays.asList( "this", "that", "and", "the", "other" );
List< String > list2 = new ArrayList();
list2.add( "something else" );
list1.addAll( list2 );
-- boom! --
It turns out that Arrays.asList() returns a fixed-size list backed by
an array and it's an "unknown UnsupportedOperationException" to attempt to
modify its size (maybe other write operations; I didn't try too hard). On the
other hand, this works:
List< String > initialList = Arrays.asList( "this", "that", "and", "the", "other" );
List< String > list1 = new ArrayList();
list1.addAll( initial );
List< String > list2 = new ArrayList();
list2.add( "something else" );
list1.addAll( list2 );
-- no boom. --
Java versions through recent times
Check out Trisha Gee's
article on Java 11
and IntelliJ IDEA .
Also, her article on the whole Java-version mess:
Using Java 11 in Production: Important Things to Know .
JVM heap memory: going over 32G, 8-byte/64-bit references
Once application heap settings reach 32G, there are problems. See
this article .
In summary, under 32G Java (object) memory references take only 4 bytes. Over 32G,
references take 8 bytes. From 32G to 37/38G is a zone that reduces the total memory
available because 20% of the heap is used to object references. The exact spot where
the JVM switches over to using (true) 8-byte (64-bit) references is XMX32767M, which
is 1M less than a full 32G.
Sorting out JNI issues
It is very difficult to troubleshoot JNI class loader issues. The only way to
determine if it's a class loader issue is to eliminate all other
UnsatisfiedLinkError cases first. If the code looks correct and is loading
the correct version of the native library without errors, including the correct
bitness package for the JRE, but is failing when creating the library context, then
the only remaining explanation is class loader issues. At that point, the environment
must be looked at to see where the offending .jar is loaded from. If this is a
web application, and the JAR is loaded from a child class loader (i.e., from the web
application's WEB-INF/lib directory), then that could point the way. In Java
web-application environments, you have to load the native library and classes from a
higher-level parent class loader, not from the individual web-application child class
loaders.
Running JVM for remote debugging...
...from the likes of IntelliJ IDEA or Eclipse.
OpenJDK: $ java -agentlib:jdwp=transport=dt_socket,address=8000 ,server=y,suspend=n
Oracle: $ java -Xdebug -Xrunjdwp:transport=dt_socket,address=8000 ,server=y,suspend=y
Once the process comes up, you can adjust settings in Edit run configurations...
for the port number, which you can choose (here 8000 , but it can be anything).
Hermetization: not leaking state
See discussion here .
Variable-length arguments...
See discussion here .
Slurping a stream...
See discussion here .
Per-thread local store
See discussion here .
How to get the line number in the caller
This easily comes up as soon as logging is pushed down from one method
(conveniently) into submethods since logging reports line numbers, but
a submethod can't give an accurate location.
Of course, there are other problems this solution doesn't solve—like the
fact that, if you've set to number lines in log4j.xml
(e.g.: see :%L and comment below),
log4j.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="false">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.EnhancedPatternLayout">
<!-- Produces: 2019-08-02 07:44:28 TRACE c.i.s.MyMethod:248 - (whatever message...) -->
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1.}:%L - %m%n" />
</layout>
</appender>
<root>
<level value="TRACE" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
...then there will be the wrong line number reported (at very least, confusingly)
no matter what your new message says when it's fixed using this solution.
/* Do this to get the current line number to pass
* down so logging submethod has it right.
*/
logTrace( Thread.currentThread().getStackTrace()[ 1 ].getLineNumber() , ... )
This has got to be somewhat expensive too, but it does avoid the instantiation
of a new exception (to get Exception.printStackTrace() , etc.).
ThreadLocal (TLS)
Here's how to do thread-local store in Java. Integer , below, could be
anything (including an instance of a very complex class hierarchy).
private static ThreadLocal< Integer > tls = new ThreadLocal<>();
public static ThreadLocal< Integer > getTls() { return tls; }
@Test
public void test()
{
tls.set( 99 );
int x = tls.get(); System.out.println( " x = " + x );
int y = tls.get(); System.out.println( " y = " + y );
tls.remove();
tls.set( 543 );
int z = tls.get(); System.out.println( " z = " + z );
tls.set( null );
tls.set( 963 );
int a = tls.get(); System.out.println( " a = " + a );
int b = tls.get(); System.out.println( " b = " + b );
tls.remove();
int c = tls.get(); // kaBOOM!
}
Output:
x = 99
y = 99
z = 543
a = 963
b = 963
java.lang.NullPointerException
at com.windofkeltia.tls.ThreadLocalTest.test(ThreadLocalTest.java:74)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
.
.
.
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Alternately, of course...
...
int b = tls.get(); System.out.println( " b = " + b );
tls.remove();
try
{
int c = tls.get();
}
catch( NullPointerException e )
{
System.out.println( "You can catch this." );
}
}
x = 99
y = 99
z = 543
a = 963
b = 963
You can catch this.
Notes
The thread-local store is created as static ;
there is no way to fetch a reference to it from the thread itself.
To fetch it, you must either pass the static reference down
or provide a static accessor (getter); code in any other class
may freely manipulate the TLS' value including destroy it.
As illustrated, once remove() or set( null)
has been called, the store is gone for any practical use; you must not
call get() without first resetting the value to something valid
(as illustrated here).
You should call remove() at some point before the thread
is abandoned; if you don't, and your TLS resource is complex (i.e.: on
the heap), you'll leak memory.
java.nio.file.Path {s }
Useful if minimal set of methods to break a filesystem path up into usable
bits.
Path path = Paths.get( "src/test/resources/fodder/xml-samples/bundle.xml" );
Path filename = path.getFileName(); // bundle.xml
Path absolute = path.toAbsolutePath(); // /home/russ/dev/fhir-json-xml/src/test/resources/fodder/xml-samples/bundle.xml
Path parent = path.getParent(); // src/test/resources/fodder/xml-samples
Path subpath = path.subpath( 2, 4 ); // resources/fodder
int count = path.getNameCount(); // 6
System.out.println( parent.toString() ); // (prints:) src/test/resources/fodder/xml-samples
How to determine the width of an integer...
...or, in other words, the number of places it occupies, the length of an array
or string needed to hold it, space in a table, etc.
Obviously, the most straightforward way would be to turn it into a string, then
measure the latter's length, but that's very expensive. There are several other
ways that are much cheaper. This one isn't the very least expensive, however,
it rejoices in being the simplest and most succinct:
int number = (whatever);
int numberOfDigitsInNumber = ( int ) Math.log10( number ) + 1;
Example outcome:
number = 4923
numberOfDigitsInNumber = 4
The nature of Enumeration< ? >
An Enumeration< String > , used for example, in conjunction with
methods of HttpServletRequest , is a "one-shot collection" in terms of
being able to be traversed.
Once traversed as below, ...
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.NoSuchElementException;
import org.junit.Test;
public class EnumerationTest
{
@Test
public void test()
{
List< String > headerNames = new ArrayList<>();
headerNames.add( "ContentType" );
headerNames.add( "Accept" );
Enumeration< String > headers = Collections.enumeration( headerNames );
try
{
// traverse 'headers' to see what's in this collection...
while( headers.hasMoreElements() )
System.out.println( headers.nextElement() );
// 'headers' is no longer useful for traversal--it is "dead" now
}
catch( IllegalArgumentException e )
{
e.printStackTrace();
}
catch( NoSuchElementException e )
{
e.printStackTrace();
}
}
}
...what's stored in headers can not be "reset" in order to get
traversed again as there are only two useful methods, both used above,
hasMoreElements() and nextElement() . If a more functional
working copy is required, then create a List from it thus:
// take 'headers' from the code in the test above...
ArrayList headerNameList = Collections.list( headers );
for( String header : headerNameList )
System.out.println( header );
// 'headerNameList' remains traversable after this point...
Both snippets of code here print the same output.
Dressing a string in floating-point...
The premise is that you have a string that could have anything in it, but it
likely has some digits. Let's say, "<2" or "0.5+" and you are interested in
the numeric stuff. Use this to remove (the "<" and "+" from the examples
here and infinite others):
final String VALUE = (some example as above);
final String ONLY_NUMERICS = VALUE.replaceAll( "[^\\d.-]", "" );
The result would be (for the two examples cited) "2" and "0.5".
Using the Decorator pattern to rename and/or dress up superclass
"Renaming" XyzClass with XClass .
I have long wondered about "renaming" classes. In C, there is typedef
that would allow me to use, for example, something called XyzPatient
in my code as XPatient without me having to create a class formally.
#define IPatient IxmlPatient
In Java, I can do this:
Code from Xyz library:
public class XyzPatient
{
public String name;
@Override
public String toString()
{
return "{ " + "name: \"" + name + "\" }";
}
}
Code from my application's shim:
public class XPatient extends XyzPatient
{
}
Code from my application:
public class PatientTest
{
@Test
public void test()
{
XPatient patient = new XPatient();
patient.name = "Jackson";
System.out.println( patient );
}
}
Formally speaking,
this doesn't walk too far down the path of "decoration" for it only renames the
class—it doesn't add anything to it. However, I have deceived you: I
don't want to decorate the superclass with additional functionality, but only
change its name.
Running test() produces:
{ name: "Jackson" }
But, I confess that I don't know how far this goes. I know that, in the past, I
have had trouble doing much with class XPatient above. This example
works well enough, but, when I have attempted to roll a class from a
third-party library whose names I don't like (usually because they collide with
classnames already in use in my code) into a "naked" decorator of this sort, I
have had some trouble.
One problem I know about is when the extending class doesn't offer a
constructor that matches one of the extended class' constructors. For example,
let's conjecture a superclass, Pojo , underneath the library's
XyzPatient , that offers an alternative constructor that we wish to
make use of:
More complete code from Xyz library:
Note the non-default constructor. What's with toString() ? just that
XyzPatient.toString() uses Pojo.toString() , but lops off the
last curly brace before adding its own field(s).
This example is a little stretched using field ____ to name the
extending POJO, but it serves to complicate the example just enough to make it
useful.
public class Pojo
{
public String ____;
public Pojo() { }
public Pojo( final String elementName )
{
____ = elementName;
}
@Override
public String toString()
{
return "{\n ----: \"" + ____ + "\" }";
}
}
public class XyzPatient extends Pojo
{
public String name;
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
String base = super.toString();
sb.append( "{ " ).append( base.substring( 0, base.length()-1 ) ) );
sb.append( "name: \"" ).append( name ).append( name ).append( "\"\n" );
sb.append( "}" );
return sb.toString();
}
}
Code from my application's shim:
public class XPatient extends XyzPatient
{
public XPatient( final String name ) { super( name ); }
}
Code from application test:
Note the use of the non-default constructor.
public class PatientTest
{
@Test
public void test()
{
XPatient patient = new XPatient( "patient" );
patient.name = "Jackson";
System.out.println( patient );
}
}
Running test() produces:
{
____: "patient"
name: "Jackson"
}
Enum reflection in Java
I wrote and tested this, then abandoned it for a better way, but I spent enough
time on it that I didn't want to lose it. The idea was to discover the
expression-language scope field inside PropertyDescriptor with the
value NONE and replace it with FLOWFILE_ATTRIBUTES .
import java.lang.IllegalAccessException;
import java.lang.NoSuchFieldException;
import java.lang.reflect.Field;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.AbstractProcessor;
public class CustomProcessor extends AbstractProcessor
{
...
public static final PropertyDescriptor BASE_SQL_QUERY = new PropertyDescriptor.Builder()
.name( "Base SQL Query" )
.displayName( "Base SQL Query" )
.description( "Base SQL query." )
.required(true)
.addValidator( StandardValidators.NON_EMPTY_VALIDATOR)
.expressionLanguageSupported( true /*ExpressionLanguageScope.FLOWFILE_ATTRIBUTES*/ )
.build();
static
{
PropertyDescriptor descriptor = BASE_SQL_QUERY;
try
{
Field field = descriptor.getClass().getDeclaredField( "expressionLanguageScope" );
field.setAccessible( true );
Object value = field.get( descriptor );
ExpressionLanguageScope scope = ( ExpressionLanguageScope ) value;
if( scope == ExpressionLanguageScope.NONE )
field.set( descriptor, ExpressionLanguageScope.valueOf( "FLOWFILE_ATTRIBUTES" ) );
field.setAccessible( false );
}
catch( NoSuchFieldException e )
{
throw new RuntimeException( e );
}
catch( IllegalAccessException e )
{
throw new RuntimeException( e );
}
}
The reason I didn't end up needing this is because of the existence of
backward-compatibility code in Apache NiFi:
private CustomProcessor processor = new CustomProcessor();
private TestRunner runner = TestRunners.newTestRunner( processor );
runner.setValidateExpressionUsage( false );
This stopped modern NiFi test code from requiring the modern mechanism of
Expression Language scope (in place of the old Boolean true/false that the
property supported using NiFi Expression Language). Running on later versions
of NiFi doesn't crash, so I'm not tempted to hack the value in.
Steps to upgrade Java on CentOS (Red Hat, etc.)
$ sudo yum install java-11
$ sudo alternatives --config java
Then, select Java 11 from the alternatives menu.