I am currently working on a method that is mapping some strings to other strings.
It has a LOT of values, and the method starts to look like this:
The method ValueHelper.isEqual() is looking for an exact match.
private IValue1 mapValue(IValue2 value2) {
if (ValueHelper.isEqual(value2.getName(), StatusValues.ACTIVE)) {
return ValueHelper.getName(StatusValues2.WORKING);
} else if (ValueHelper.isEqual(value2.getName(), StatusValues.INACTIVE)) {
return ValueHelper.getName(StatusValues2.NOT_WORKING);
} else if (ValueHelper.isEqual(value2.getName(), StatusValues.IN_SERVICE)) {
return ValueHelper.getName(StatusValues2.SERVICE);
}
}
At current point I have 10 else-if code blocks.
What is the best way to make this method simpler and shorter? Extracting the values to a Key-Value map? Or maybe another option?
A map would do fine I guess. You could also think about switch-case to make it a little less verbose:
private IValue1 mapValue(IValue2 value2) {
switch(value2.getName()) {
case StatusValues.ACTIVE: return StatusValues2.WORKING;
case StatusValues.INACTIVE: return StatusValues2.NOT_WORKING;
case StatusValues.IN_SERVICE: return StatusValues2.SERVICE;
default: throw new RuntimeException();
}
The OOP approach is to have this method in your interface IValue2:
interface IValue2 {
...
String getName();
IValue1 mapValue();
}
Each implementing object now must override this abstract method. This maybe requires some implementation changes. You could - for example - have a ActiveValue2 class:
class ActiveValue2 implements IValue2 {
...
public String getName() {
return StatusValues.ACTIVE;
}
public IValue1 mapValue() {
return ValueHelper.getName(StatusValues2.WORKING);
}
}
You now simply call the mapValue method on an IValue2-types variable. Done.
Yes, having a Map of <StatusValues, StatusValues2> would be the right approach.
You will simply look for the current StatusValue as the key and receive the matching StatusValue2
You might consider converting your strings to an enum:
public enum Status {
ACTIVE("active", WORKING),
INACTIVE("inactive", NOT_WORKING),
IN_SERVICE("inservice", SERVICE),
...
private final String name;
private final Value value;
Status(String name, Value value) {
this.name = name;
this.value = value;
}
public static Optional<Value> getValueForName(String name) {
return Arrays.stream(values())
.filter(v -> isEqual(name, this.name))
.findAny();
}
}
Use guava Immutable Map. They are faster and take less memory than standard java HashMap.
Related
I have such enum class in java
public enum MockTypes
{
// Atlantis mocks
ATLANTIS_VERIFY("ATLANTIS", "verify"),
ATLANTIS_CREATE_RECORD("ATLANTIS", "createRecord"),
...
private String m_adaptor;
private String m_step;
private MockTypes( String adaptor, String step)
{
m_adaptor = adaptor;
m_step = step;
}
public String getAdaptor()
{
return m_adaptor;
}
public String getStep()
{
return m_step;
}
I have to implement method that returns enum value by adaptor and step parameter.
public MockTypes getMockTypeByName(String adaptor, String step)
but I have no idea how. Could someone help me?
public MockTypes getMockTypeByName(String adaptor, String step)
{
for(MockTypes m : MockTypes.values())
{
if(m.getAdaptor().equals(adaptor) &&
m.getStep().equals(step)) return m;
}
return null;
}
If you want a "constant-time" solution that doesn't involve looking up values, your best option is to initialize a constant Map in a static block in the MockType class.
If you're up for using Guava, it'll actually be relatively pleasant:
public enum MockType {
...
private static final ImmutableTable<String, String, MockType> LOOKUP_TABLE;
static {
ImmutableTable.Builder<String, String, MockType> builder =
ImmutableTable.builder();
for (MockType mockType : MockType.values()) {
builder.put(mockType.getAdaptor(), mockType.getStep(), mockType);
}
LOOKUP_TABLE = builder.build();
}
public static MockType getMockType(String adaptor, String step) {
return LOOKUP_TABLE.get(adaptor, step);
}
}
(Disclosure: I contribute to Guava.)
The alternative is going to be relatively similar -- construct a Map<String, Map<String, LookupType>> in a static block, and do lookups from there -- though it's going to require somewhat more work.
You can use enum's values() method to obtain a list of all the defined values. You can then loop through this list and find the values you're interested in that match the ones sent as parameters to the method.
A little background as to what I'm trying to achieve:
I'm parsing JSON (over 15GB) and I must store it in memory so any wrappers and extra data is not welcomed, due to the framework and interfaces used within it I must provide functionality to access fields by name. By replacing some String with Enum, Integer with int, Double with double, etc. I'm able to shave about 90% of memory footprint (in comparison with Jackson).
I'm looking to efficiently access the fields at runtime in Java by their name. I'm aware of reflection, but for my case its performance is simply unacceptable, so I don't want to use it.
If it makes the problem easier to solve I'm not too bothered about setting the fields values. I also know at compile time the names of supported fields.
I don't want to store everything in a map i.e. Map<String,Object> due to the memory footprint of boxed object, but I don't mind returning them in a boxed form.
I'm sure this problem was encountered by others and I'm interested in any clever solutions - cleverer than tons of if ... else ... statements.
Let's say the interface to implement is:
public interface Accessor {
Object get(String fieldName);
}
The Object returned by get can be of any type including enum. A naive implementation would be:
public class TestObject implements Accessor {
public enum MyEnum {ONE, TWO, THREE};
private final MyEnum myEnum;
private final int myInt;
private final double myDouble;
private final String myString;
public TestObject(MyEnum myEnum, int myInt, double myDouble, String myString) {
this.myEnum = myEnum;
this.myInt = myInt;
this.myDouble = myDouble;
this.myString = myString;
}
#Override
public Object get(String fieldName) {
if ("myEnum".equals(fieldName)) {
return myEnum;
} else if ("myInt".equals(fieldName)) {
return myInt;
} else if ("myDouble".equals(fieldName)) {
return myDouble;
} else if ("myString".equals(fieldName)) {
return myString;
} else {
throw new UnsupportedOperationException(); // Or could simply return null
}
}
}
What you want is a mapping from a fieldName to a value, the type of which is determined by the fieldName. You know the set of field names up-front, so this is an ideal task for an Enum.
If you don't like the idea of hard-coding each field as an enum, then the variation would be an enum-per-type (MY_FIELD1 becomes MY_ENUM), with a mapping from fieldName to this EnumType.
In the code below I'm making assumptions about the relationship between fieldName and TestObject. Specifically it looks like TestObject is presenting various types of the same value (surely where reasonable), as opposed to a separate value for each field name?
So, to the code:
Rewrite:
#Override
public Object get(String fieldName) {
MyField field = MyField.mapNameToField(fieldName);
if (field == null)
throw new UnsupportedOperationException(); // Or could simply return null
return field.getValue(this);
}
Given (something like):
enum MyField {
MY_FIELD1("myField1") {
public Object getValue(TestObject obj) { return obj.myEnum; }
},
MY_FIELD2("myField2") {
public Object getValue(TestObject obj) { return obj.myInt; }
},
...
;
public abstract Object getValue(TestObject obj);
public String getName() { return name; }
public static MyField mapNameToField(String name) { return map.get(name); }
static {
map = new HashMap<String,MyField>();
for(MyField value: values()) {
map.put(value.getName(), value);
}
}
private MyField(String fieldName) { name = fieldName; }
private String name;
private static Map<String, MyField> map;
}
I've never used this, but looks promising:
http://labs.carrotsearch.com/download/hppc/0.4.1/api/
"High Performance Primitive Collections (HPPC) library provides typical data structures (lists, stacks, maps) template-generated for all Java primitive types (byte, int, etc.) to conserve memory and boost performance."
In particular, the Object{Type}OpenHashMap classes might be what you're looking for:
ObjectByteOpenHashMap
ObjectCharOpenHashMap
ObjectDoubleOpenHashMap
ObjectFloatOpenHashMap
ObjectIntOpenHashMap
ObjectLongOpenHashMap
ObjectShortOpenHashMap
I imagine you would have all 7 of these defined as fields (or whatever subset of them you like), and you would probe each one in turn to see if the key was present for that type of primitive value. E.g.,
if (byteMap.containsKey(key)) {
return byteMap.lget(); // last value saved in a call to containsKey()
} else if (charMap.containsKey(key)) {
return charMap.lget();
} else if {
// and so on...
}
Notice they have their own special lget() method call to optimize the containsKey() / get() usage pattern so typical with maps.
This question already has answers here:
How to return multiple objects from a Java method?
(25 answers)
Closed 9 years ago.
I'm trying to do something like this:
public void <String,int> getItem
{
return <"Jen",23>;
}
I know I can use a custom class, but how I would I return two results in one function call.
1 - Is the above template function possible in java, and how would by caller get part 1 of it and part 2 later.
2 - Can I do it using an associative array like in actionscript?
3 - Can I do it using a hashmap of some sort?
4 - What are other possible ways are there
I attempted all three ways, but one way or another syntax is hitting me. So if anyone can give clear examples
Java functions always return a single value, so your only option is to return a "collection" object which contains multiple values, such as an Array or a proper Collection. For example:
public Object[] getItem() { return new Object[] { "Jen", 23 }; }
public Collection<Object> { return Arrays.asList("Jen", 23); }
Although, a typical pattern in Java is to return a custom type which encapsulates your values, e.g.:
public class NameAge {
public final String name;
public final int age;
public NameAge(String name, int age) {
this.name = name;
this.age = age;
}
}
// ...
public NameAge getItem() { return new NameAge("Jen", 23); }
Or more generally:
public class Pair<X, Y> {
public final X x;
public final Y y;
public Pair(X x, Y y) {
this.x = x;
this.y = y;
}
}
// ...
public Pair<String,Integer> getItem() {
return new Pair<String,Integer>("Jen", 23);
}
Of course, there are serious implications regarding hashing (equality and hash code) if you want to use these custom types as hash keys.
I like using generics! Create your own class and return an instance of it:
public class Tuple<T,V>
{
public T item1;
public V item2;
public Tuple(T i1, V i2)
{
item1 = i1;
item2 = i2;
}
}
Then you create your method:
public Tuple<String, int> getItem()
{
return new Tuple<String, int>("Jen", 23);
}
Java does not allow for multiple return statements. The best practice I believe is to create a custom object. What you have here suggests some sort of Person class, a la
public class Person {
int Age;
String Name;
}
Returning an object will make it more intuitive what you are doing as well.
You can return a Bundle.
public Bundle getItem(){
Bundle theBundle = new Bundle();
theBundle.putString("name","Jen");
theBundle.putInt("age",23);
return theBundle;
}
Usually, if you need to return two values from one function - it's a code smell. Try to refactor your code so that every function always return just one value. Keep in mind that no return value (void) is also a code smell, but less critical.
The proper way would be to create a class for your return set:
public class ReturnSet {
private String str;
private int num;
public ReturnSet(String _str, int _num) {
str = _str;
num = _num;
}
//add getters and setters
...
}
Then your function would look like
public ReturnSet getItem() {
...
return new ReturnSet(strValue, intValue);
}
Of course, you can fudge things by having your function return an array of Object, but this would be a rather bad code:
public Object[] getItem() {
Object[] result;
//allocate it, get data;
...
result[1] = strValue;
relult[2] = new Integer(intValue);
return result;
}
You can even return a hashmap with one element in it:
public Map getItem() {
Map result;
//allocate it, say as hashmap, get data;
...
result.put(strValue, new Integer(intValue));
return result;
}
Then in the caller, the key of the map would be the first part and the value would be the second.
While there are may be many ways of doing things like that, the first one is the right approach.
If a method returns something, then its return type must be this something:
public MyCustomObject getItem();
or
public Object[] getItem():
or anything else wher you can store the results.
But Java is a statically typed OO language. A custom class is the way to go.
You can also return one value the regular way and other(s) by using a "return" parameter:
class C {
Type2 value; // omitted getter and setter for brevity
}
Type1 f1(C returnParameter, String otherParameters...)
{
// function body here
returnParameter.value=returnValue2; // store the second result
return returnValue1; // return the first result
}
// usage
Type1 result1;
Type2 result2;
C helper = new C();
result1=f1(helper, "foo", "bar");
result2=helper.value;
For more results either use several "helper" objects or one that can hold several values.
I am myself looking for a most elegant solution (in my case one return type is a Collection and the other is an integer number-any variant of it is OK).
I've been struggling with this for a while and have yet to find an answer. As a result, my brain is somewhat muddled, so pardon me if I make a dumb mistake.
I'm trying to implement a typed INI parser, that will parse this kind of file:
[section1]
<int>intkey=0
<float>floatkey=0.0
<str>stringkey=test
[section2]
<float>x=1.0
<float>y=1.0
<float>z=0.0
In doing so, I have a central class named Config, which handles the basic reading and writing operations. One of the methods of Config is called get(String section, String key), which ideally would return a value appropriate for the requested section-key pair, like so:
Config cfg = new Config("test.ini");
cfg.get("section2", "x"); // 1.0, not "1.0" or some Object that technically represents the float
cfg.get("section1", "intkey"); // 0
cfg.get("section1", "strkey"); // "test"
I'm currently using an enum to handle the conversion of the String to various types, with an abstract method overridden by the different types:
enum Type
{
INTEGER ("int") {
public Object parse(String value) {
try
{
return Integer.parseInt(value);
} catch (NumberFormatException e)
{
return null;
}
}
},
FLOAT ("float") {
public Object parse(String value) {
try
{
return Float.parseFloat(value);
} catch (NumberFormatException e)
{
return null;
}
}
},
STRING ("str") {
public Object parse(String value) {
return value;
}
};
public final String name;
Type(String name)
{
this.name = name;
}
private static HashMap<String, Type> configMap = generateConfigMap();
private static HashMap<String, Type> generateConfigMap()
{
HashMap<String, Type> map = new HashMap<String, Type>();
for (Type type : Type.values())
map.put(type.name, type);
return map;
}
public static Type get(String name)
{
return configMap.get(name);
}
abstract public Object parse(String value);
}
Unfortunately, parse(String value) returns an Object, and when passed out of Config, requires a cast or similar, and ideally this would be self-contained.
If I'm going about this completely wrong and there's a more flexible or simple way to code it, please let me know. I'm open to suggestions. Though I would like to know if there's a way to do this. Maybe with generics...?
Note: I know I'm missing imports and the like. That's not why I'm posting here.
Here's the thing. If the code that calls config.get() doesn't know what type to expect, you can't possibly return anything other than Object since the calling code doesn't know what to expect. Of course you'll have to cast.
Now, if you wanted to design Config in a way that the caller did know what type it was asking for, than that becomes a bit easier. The easiest approach then is to do something like this:
public class Config {
public int getInt(String a, String b) {
return ((Integer)get(a, b)).intValue();
}
}
But until the caller knows what to expect, you really gain nothing from avoiding casts.
If you want to return a a type of object depending on what you get you can do this:
public <T extends MyObject> T myMethod(Class<T> type) {
return type.cast(myObj);
}
Can I contain two different types in a collection? For example, can I have List< String U Integer > ?
Short answer? No. You can (of course) have a List of Objects, but then you can put anything in it, not just String or Integer objects.
You could create a list of container objects, and that container object would contain either an Integer or String (perhaps via generics). A little more hassle.
public class Contained<T> {
T getContained();
}
and implement Contained<Integer> and Contained<String>.
Of course, the real question is why you want to do this? I would expect a collection to contain objects of the same type, and then I can iterate through and perform actions on these objects without worrying what they are. Perhaps your object hierarchy needs further thought?
Nope. You have a couple of alternatives, though:
You can use a List < Object > and stash whatever you like; or
You can use a List < Class-with-2-members > and put your data in one of those class members.
EDIT: Example.
class UnionHolder {
public String stringValue;
public int intValue;
}
List < UnionHolder > myList
...
Of course you'll need a bit of additional code to figure out which kind of data to pull out of the UnionHolder object you just got out of your list. One possibility would be to have a 3rd member which has different values depending on which it is, or you could, say, have a member function like
public boolean isItAString() { return (this.stringValue != null }
If you are doing something like functional programming in Java 8 or above, you may want to try JavaSealedUnions:
Union2.Factory<String, Integer> factory = GenericUnions.doubletFactory();
Union2<String, Integer> strElem = factory.first("hello");
Union2<String, Integer> intElem = factory.second(3);
List<Union2<String, Integer>> list = Array.asList(strElem, intElem);
for (Union2<String, Integer> elem : list) {
elem.continued(
strElem -> System.out.println("string: " + strElem),
intElem -> System.out.println("integer: " + intElem));
}
Haven't tested this, but I think you got the idea.
In addition to the nice answers already provided ...
Possibly, you have the two data types in your algorithm. But you may not have to put them in the same list...
Creating two typed lists could be the clearer for your algorithm, you would still keep the "type-safeness" and carry all your data. Two code samples follow, the second grouping the two lists in a MyData object.
public class Algorithm1 {
public void process(List<String> strings, List<Integer> integers) {
...
}
}
--------------------------------------
public class DataPair {
public List<String> strings;
public List<Integer> integers;
}
public class Algorithm2 {
public void process(DataPair dataPair) {
...
}
}
what you're decribing is the perfect use case for the Visitor pattern
100% statically type-checked
doesn't need Java 8 or above
usage:
List<UnionType> unionTypes = Arrays
.asList(new StringContainer("hello"), new IntegerContainer(4));
for (UnionType unionType : unionTypes) {
unionType.when(new UnionType.Cases<Integer>() {
#Override
public Integer is(StringContainer stringContainer) {
// type-specific handling code
}
#Override
public Integer is(IntegerContainer integerContainer) {
// type-specific handling code
}
});
}
boilerplate code:
interface UnionType {
<R> R when(Cases<R> c);
interface Cases<R> {
R is(StringContainer stringContainer);
R is(IntegerContainer integerContainer);
}
}
class StringContainer implements UnionType {
private final String value;
public StringContainer(String value) { this.value = value; }
public String getValue() { return value; }
#Override
public <R> R when(Cases<R> cases) {
return cases.is(this);
}
}
class IntegerContainer implements UnionType {
private final Integer value;
public IntegerContainer(Integer value) { this.value = value; }
public Integer getValue() { return value; }
#Override
public <R> R when(Cases<R> cases) {
return cases.is(this);
}
}
No. Think about it this way: with generics, the whole idea is to provide type safety. That would not be possible if you could put Objects of different types into it.
You can use the non-generic java.util.List for your purpose.
If you want to ensure that only String or Integer objects enter the list, you could create your own List implementation like so:
public class MySpecialList {
private List list= new LinkedList();
...
public void add(final String string) {
list.add(string);
}
public void add(final Integer integer) {
list.add(integer);
}
...
// add rest of List style methods
}
Drawback: you loose the List interface clarity...