Java Tips String comparison

A Java tips during String comparison. We must use .equals() instead of ==.

Using ==, it checks for reference equality.

Using .equals(), it checks for the value equality.

For example,


String a = "YongHao";
String b = "YongHao";
System.out.println(a == b);
System.out.println(a.equals(b));

OK, if you run above code, you will see true true.

But,


String a = new String("YongHao");
String b = new String("YongHao");
System.out.println(a == b);
System.out.println(a.equals(b));

You will get false true.

In first case, a = “YongHao” and b = “YongHao”, as Java will perform String interning by default. String interning meant create a single copy of String and stored in String Constant Pool. So a and b will point to same object in this case, so does a == b is true. String constant pool is fixed size. The reason to create String constant pool is to save space and memory. Note, this is not always guarantee String interning will happens, this is based on JVM setting.

In second case, new String(“YongHao”) guarantee always new object, a and b points to different objects, so a == b return false, but a.equals(b) return true, which is expected.

Conclusion, in Java, when compare String, KEEP IN MIND, always use .equals()

JVisualVM and Eclipse Memory Analyzer a Java Dev Tools

JVisualVM is an open source software to analyze CPU Usage / Memory Usage in real time of a JVM application.

Eclipse Memory Analyzer is an open source software to analyze memory leaks. By passing the Java heap dump this tool will help to pinpoint where is the memory leaks and producing the report which aids developers to fix the bugs.

I am experienced using Eclipse Memory Analyzer along with JVisualVM in a production environment. Last time the production server will went down after running one weeks without any signs. We couldn’t find any clues how the system went down. We then used JVisualVM to monitor the JVM based application server. We got the memory and CPU usage in real time. Then when the server was went down, we quickly open JVisualVM and generate heap dump file. We then passed this heap dump feed into Eclipse Memory Analyzer. After that, Memory Analyzer will tell us where is the memory leaks, which Java object/instances eating up most spaces, then we know how to solve the problem. Finally, after the fix, no more server went down issue.

Additional note, I experienced solved a memory leaks issues on an Apache Tomcat. Technically, in order to enable JVisualVM Monitoring on Apache Tomcat, we need to enable JMX Port in Apache Tomcat conf/server.xml setting. Then open JVisualVM to connect to this JMX Port. Enable JVisualVM Monitoring via JMX on production server is safe as this will not degrade server performance. Same can applies to other JVM based application. This is proven by industry standard. So I strongly recommends.

JVisualVM: http://docs.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html

Eclipse Memory Analyzer: http://www.eclipse.org/mat/

Feel free contact me if you need any expertise suggestions.

Java utility to get class version compiled for

Want to check out what is the Java class version compiled for, here comes several ways.

1) javap tool comes along with JDK/JRE
Assume you have a Test.java source code with compiled version of Test.class.
Open your terminal, type
In Unix:
javap -verbose Test | grep "version"
In Windows:
javap -verbose Test | find "version"

Note down Major version number.

Refer to this table:

Major Minor Java Platform Version
45 3 1.0
45 3 1.1
46 0 1.2
47 0 1.3
48 0 1.4
49 0 1.5
50 0 1.6
51 0 1.7
52 0 1.8

2) DataInputStream

There is another clever guy on StackOverFlow just read Java byte class into DataInputStream, and getting the magic number directly yield the minor and major. I copied the code here.

DataInputStream in = new DataInputStream(new FileInputStream(filename));
int magic = in.readInt();
if(magic != 0xcafebabe) {
	System.out.println(filename + " is not a valid class!");;
}
int minor = in.readUnsignedShort();
int major = in.readUnsignedShort();
System.out.println(filename + ": " + major + " . " + minor);
in.close();

3) Unix od
Just below the Java code, other guys found a Unix command line to get the magic number.


od -x HelloWorldJava.class |head -2

I ran this code on my box I found:

od -x Test.class | head -2
0000000      feca    beba    0000    3400    0f00    000a    0003    070c
0000020      0d00    0007    010e    0600    693c    696e    3e74    0001

feca beba is a magic number, 0000 3400 represents Java SE 8.

Check it out my Java version:
java -version

java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

What’s use for this check?

I experienced to maintain some legacy code on my box, with my Eclipse set to higher Java JDK version, when deploy to production server it encountered error showing something like “unrecognized class file version”. By using this check I can check the existing java class version on the server, and then go back to my Eclipse and adjust up/down (most probably down) my Java JDK version and compile a new one against it.

Trying on Java 8 Stream Parallel

I had been trying on Java 8 Stream Parallel.

Refer following code:

import java.util.*;
public class Test {
	public static void main(String args[]) {
		List list = new ArrayList<>();
		list.add(new Employee("First", "YongHao"));
		list.add(new Employee("Second", "YongHao"));
		list.add(new Employee("Third", "YongHao"));
		
		list.stream().sorted((e1, e2) -> e1.getFirstName().compareTo(e2.getFirstName()))
		        .forEach(System.out::println);
		
		System.out.println("--------------");
		
		list.stream().parallel().sorted(Comparator.comparing(e -> e.getFirstName()))
		        .forEachOrdered(System.out::println);
		        
		        
	}
	
	public static class Employee {
		String firstName;
		String lastName;
		public Employee(String firstName, String lastName) {
			this.firstName = firstName;
			this.lastName = lastName;
		}
		public String getFirstName() {
			return firstName;
		}
		public String getLastName() {
			return lastName;
		}
		public String toString() {
			return firstName + " " + lastName;
		}
	}
}

The result will be:
➜ java2 javac Test.java
➜ java2 java Test
First YongHao
Second YongHao
Third YongHao
————–
First YongHao
Second YongHao
Third YongHao

Look at first:

list.stream().sorted((e1, e2) -> e1.getFirstName().compareTo(e2.getFirstName()))
.forEach(System.out::println);

It first returns the list as a stream, sort the list using the lambda expression and then iterating the list and print its output.

Look at second:

list.stream().parallel().sorted(Comparator.comparing(e -> e.getFirstName()))
.forEachOrdered(System.out::println);

Notice, after returned stream-ed list, there is a chained parallel(), which will actually doing background task distribution fully utilizing your system cores. And notice, forEachOrdered method at the end, which guarantees the ordered result be returned. If we replace forEachOrdered to forEach, you will see random order be returned. Because forEach method cannot guarantee ordered result when doing parallel operation.

Another note, see the chained operation, from the list, to stream(), parallel(), sorted(), at the point Java had not yet execute anything, list.stream() did return a stream-ed list, or more formally, a lazy list, the actual execution started when we call forEach or forEachOrdered function.

I did some simple benchmark to measure the speed for these two, one without parallel and one with parallel.

Here come modified code:

import java.util.*;
public class Test {
	public static void main(String args[]) {
		List list = new ArrayList<>();
		generateList(list);
		long start = System.currentTimeMillis();
		list.stream().sorted((e1, e2) -> e1.getFirstName().compareTo(e2.getFirstName()))
		        .toArray();
		System.out.println("Elapsed:"+(System.currentTimeMillis() - start));
		System.out.println("--------------");
		start = System.currentTimeMillis();
		list.stream().parallel().sorted(Comparator.comparing(e -> e.getFirstName()))
		        .toArray();
		System.out.println("Elapsed:"+(System.currentTimeMillis() - start));        
	}
	
	private static void generateList(List list) {
		for(int i = 0; i < 2000000; i++) {
			Employee e = new Employee("EMP" + i, "YONGHAO");
			list.add(e);
		}
	}
	
	public static class Employee {
		String firstName;
		String lastName;
		public Employee(String firstName, String lastName) {
			this.firstName = firstName;
			this.lastName = lastName;
		}
		public String getFirstName() {
			return firstName;
		}
		public String getLastName() {
			return lastName;
		}
		public String toString() {
			return firstName + " " + lastName;
		}
	}
}

The result will be:
java2 javac Test.java
➜ java2 java Test
Elapsed:1901
--------------
Elapsed:337
➜ java2 java Test
Elapsed:296
--------------
Elapsed:494
➜ java2
➜ java2 java Test
Elapsed:288
--------------
Elapsed:1425
➜ java2
➜ java2 java Test
Elapsed:1834
--------------
Elapsed:422

OK, the result showed that... well, most of the time parallel operation faster, actually it should be faster when operating quite big data. Because it distributes the tasks to multiple cores.

OK, conclusion, worth to learn this new technology.

Stream and Lambda is the new features added in Java 8. A lot more to explore.