Comparing int with character constant in Java

I have a binary file that uses 4 character sets to form integers that have a "value". For example, 4 bytes of '0005' , which is equal to 808464437 in integer form.

I would rather present them in my Java code as '0005' rather than 808464437. I also do not want to set constants like final int V0005 = 808464437 .

In C ++, I can do the following:

 fileStream->read((byte*) &version, 4); //Get the next bytes and stuff them into the uint32 version switch (version) { case '0005': //do something case '0006': //do something case '0007': //do something } 

In Java, my problem is not to read 4 bytes and put them in some data type. My problem is comparing some data type with const char '0005' array.

How to compare int or any form with const array, for example '0005' in Java? I need to do this as efficiently as possible!

+7
source share
7 answers

The most efficient way would be to work with integers - something like final int V0005 = 0x30303035 (a combination of several different ideas discussed here) would be manageable. Java simply does not have the type of whole literals you are looking for.

If you really want to work with strings, you first need to read the characters in an array of bytes, and then convert them to String (standard encoding usually works, since it is a superset of ASCII). However, this will be less effective.

You can write a function to calculate constant values ​​from primes (e.g. 5) for better readability, but this is probably too large.

+1
source

Thanks for explaining your answer.

Here's how to convert from 4 bytes to int, which can then be compared to the int in question:

  int v0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get(); 

This, unfortunately, is the only way I can do this ... maybe not as effective as you want, but maybe this is what you need, nonetheless.

I would like to suggest some of them as "constants" in one of your classes:

 public static final int V0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get(); public static final int V0006 = ByteBuffer.wrap("0006".getBytes()).asIntBuffer().get(); public static final int V0007 = ByteBuffer.wrap("0007".getBytes()).asIntBuffer().get(); public static final int V0008 = ByteBuffer.wrap("0008".getBytes()).asIntBuffer().get(); 

And then turn on V0005, etc., since including a primitive type (int) is efficient.

+4
source

A char array in java is nothing but a String in java. You can use string in wiring closets in Java7, but I don't know the effectiveness of comparisons.

Because only the last element of your char array makes sense, you can make a switch case with it. Something like

 private static final int VERSION_INDEX = 3; ... char[] version = // get it somehow switch (version[VERSION_INDEX]) { case '5': break; // etc } ... 

EDIT A more object-oriented version.

  public interface Command { void execute(); } public class Version { private final Integer versionRepresentation; private Version (Integer versionRep) { this.versionRepresentation = versionRep; } public static Version get(char[] version) { return new Version(Integer.valueOf(new String(version, "US-ASCII"))); } @Override public int hashCode() { return this.versionRepresentation.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof Version) { Version that = (Version) obj; return that.versionRepresentation.equals(this.versionRepresentation); } return false; } } public class VersionOrientedCommandSet { private final Command EMPTY_COMMAND = new Command() { public void execute() {}}; private final Map<Version, Command> versionOrientedCommands; private class VersionOrientedCommandSet() { this.versionOrientedCommands = new HashMap<Version, Command>(); } public void add(Version version, Command command) { this.versionOrientedCommands.put(version, command); } public void execute(Version version) throw CommandNotFoundException { Command command = this.versionOrientedCommands.get(version); if (command != null) { command.execute(); } else { throw new CommandNotFoundException("No command registered for version " + version); } } } // register you commands to VersionOrientedCommandSet char[] versionChar = // got it from somewhere Version version = Version.get(versionChar); versionOrientedCommandSet.execute(version); 

a lot of code hehe. You will have a small warm-up cost, but if you program several times, you will get efficiency with a map: P

+3
source

Having received some from some other answers (@marvo and @vikingsteve), I came out with this:

 public enum Version { V0005 { @Override public void doStuff() { // do something } }, V0006 { @Override public void doStuff() { // do something else } }; private final int value; private static final Map<Integer, Version> versions = new HashMap<>(); private Version() { final byte[] bytes = name().substring(1).getBytes(); //remove the initial 'V' this.value = ByteBuffer.wrap(bytes).asIntBuffer().get(); } static { for (Version v : values()) { versions.put(v.value, v); } } public abstract void doStuff(); public Version valueOf(int i){ return versions.get(i); } } 

This provides a good object-oriented approach, as the action is encapsulated by the presentation of the data. Each Constant decides what to do when doStuff is called, avoiding switching to client code. The following is used:

 int code = readFromSomewhere(); Version.valueOf(i).doStuff(); 

The valueOf finds Version in the map, which is populated when the class loads. I don’t know how effective this is, since int gets boxing in Integer , but , you only know when you are a profile , everything else is a pure assumption. Also note that integer values ​​are calculated for you in the constructor, so you just need to define enums with the correct name, and this will be done automatically.

+2
source

Are you looking for something like value1.intValue() == value2.intValue() ? Or you can just type in the text.

 char myChar = 'A'; int myInt = (int) myChar; 

The same cane is different.

 int myInt = 6; char myChar = (char) myInt; 
+1
source

The only way is a very inefficient byte [] for string conversion.

 switch (new String(version, "US-ASCII")) { case "0005": break; ... } 

Using a map (Hash-) instead will make it faster.

But I think that you will not be satisfied with this decision.

+1
source

Given that this seems to be a version string in a package or something else, the number of values ​​is finite and has a reasonable amount. Thus, they can be encapsulated in an enumeration. Enumeration can encapsulate efficient code for converting from four bytes of input to a representative list. (My code for performing this conversion is not necessarily the most efficient. Perhaps, given the small number of versions, a good internal array or mapping ints to enums will work.)

 class enum Version { UNKNOWN(0), V0005(0x30303035), // whatever the int value is V0006(0x30303036); private int id; private Version(int value) { id = value; } public static Version valueOf(int id) { for (Version version : values()) { if (version.getId() == id) { return version; } } return UNKNOWN; } public static Version valueOf(String sId) { return valueOf(computeId(sId)); } public static int computeId(String sId) { // efficiently convert from your string to its int value } } 

Then in my switch:

 String s = methodThatReadsFourChars(...); switch (Version.valueOf(s)) { case V0005 : doV0005Stuff(); break; case V0006 : doV0006Stuff(); break; default : throw new UnknownVersionException(); 
+1
source

All Articles