Runtime populated enum-like class - java

I have many objects using few classes (means elements visual categorization like in html+css). Classes are not known at compile-time and they are used in conditions many times.
To improve performance I've got one solution:
public class ElementClass {
private static final Map<String, ElementClass> classes = new HashMap<>();
public final String name;
public final String lowerName;
public ElementClass(String name, String lowerName) {
this.name = name;
this.lowerName = lowerName;
}
public static ElementClass get(String name) {
String lower = name.toLowerCase();
ElementClass c = classes.get(lower);
if (c == null) {
c = new ElementClass(name, lower);
classes.put(lower, c);
}
return c;
}
}
The method get is used very less than comparison of ElementClass variables. It is in parsing configurations and for some static variables. I'm not sure if this is the best way to go, because I'm Java beginner.
The examples usage of ElementClass:
// contains element styles based on it's class
Map<ElementClass,ElementStyle> styles;
void exampleFunction() {
ElementClass c = ElementClass.get("special");
for( Element e : elements ) {
if( e.cls == c ) doSomethingSpecial();
}
}

This would be a textbook implementation of a cache. If there aren't many ElementClasses and if your program is single-threaded, this will be enough.
I don't see the need to keep the lowercase name inside the ElementClass. It is enough to use it as the map key. I also assume there's more to the ElementClass in your project since now it just contains a name.
Update
After clarification it became obvious that you do indeed only intend to use the String name. In such a case it would be much better to make each Element just contain its lowercase name, but interned:
public Element(String name) {
this.name = name.toLowerCase().intern();
}
Then you can compare element.name == "special" and be guaranteed to match any names that are equal to "special".

Related

How to specify a class property from a string in java

So I am reading from a file with scanner it has the similar format:
title, name, age
Mr, Matthew, 20
mr, Paul, 30
miss, Anne, 24
CSV^
class person{
String name, title;
int age;
public crimeData(String csv){
String[]list = csv.split(",", -1);
name = list[0];
title = list[1];
age = list[2];
}
}
Console Program
Scanner input = new Scanner(System.in);
System.out.println("Please select what data you want to load:");
String selection = input.next();
int temp = 0;
for(int i=0; i< header.length; i++){
if(header[i].equals(selection)){
temp = i;
break;
}
}
temp will give us the index of the option specified so if it is 2 we will want to access the age property
When my console application runs I prompt them(the user) for the data that they want.
So they may enter "age" So I am lost on how I may take this "age" String and access the person object with it.
The ideal case for the program output should be: 20,30,24 going through each age and printing
I take their input so String input = scanner.nextLine();
Then I loop through my array of person objects to get the index of the input. Once I have this index I then want to access the property of person at the index. So like if my index was 1 I would want to access the property 'name'.
In javascript I could take the string and say person['age'] although java's a whole different story. I have looked into java's "reflection API" although it's a heavy learning curve.
I have looked into java's "reflection API" although it's a heavy learning curve.
Well, Reflection is the way to go. It's widely used in many frameworks.
But perhaps a simpler solution will fit your needs. Use a switch to decide which attribute to return, and encapsulate this in a method of the Person class:
class Person {
private String name, title;
private int age;
public loadData(String csv){
String[] list = csv.split(",");
name = list[0];
title = list[1];
age = Integer.parseInt(list[2]);
}
public Object attribute(String attribute) {
switch (attribute) {
case "name": return this.name;
case "title": return this.title;
case "age": return this.age;
default: throw new RuntimeException("Invalid attribute: " + attribute);
}
}
}
Encapsulating the switch inside the method is in line with OOP principles, since it hides how attributes are stored from other objects, only exposing an interface to query them. Reflection breaks all encapsulation.
Though in general I am not in favor of using Map for holding fields for an object, if the number of properties is large and could even potentially vary across CSV files (e.g., some file has the University a person attended, another does not), then using a Map to hold the properties might be appropriate.
In this case, one would define a simple Person class:
public class Person {
Map<String, String> props = new HashMap<>();
public void addProperty(String propertyName, String value) {
// could add error checking to ensure propertyName not null/emtpy
props.put(propertyName, value);
}
/**
* returns the value of the property; may return null
*/
public String getProperty(String propertyName) {
return props.get(propertyName);
}
}
If it is know that certain attributes/properties will always be loaded, then accessors such as getName() could be added:
public String getName() {
return props.get("name");
}
public int getAge() {
String age = props.get("age");
// or throw exception if missing
return (age != null ? Integer.parseInt(age) : -1);
}
Though note I would expect name to not be a single entry for most datasets, as there typically would be last name, first name, etc. Nonetheless, the pattern for a limited number of commonly expected values is the same. Also, you can adapt so that you could get integer values directly for certain well-known fields.
Then, when you parse the file, you keep the title row that has the attribute definitions. Then for each row that you subsequently read, you create a new Person object, and then add the properties in order.
List<Person> allPersons = new ArrayList<>();
while ( (line = READ_NEXT_LINE) ) {
// NOTE: this is not a safe way to handle CSV files; should really
// use a CSV reader as fields could have embedded commas
attrs[] = line.split(",");
Person p = new Person();
for (int i = 0; i < titleRow.length; ++i) {
p.addProperty(titleRow[i], attrs[i]);
}
allPersons.add(p);
}
You can then get a specific Person by Person myPerson = allPersons.get(index_of_person), and much akin to the way you would have used Javascript, you can do String val = myPerson.getProperty("age").
If you need to search by a given attribute, you can then stream/loop over the allPersons and check of equivalence based upon a given property.
// find all people of a given age
List<Person> peopleAge20 = allPersons.stream()
.filter(p -> p.getAge() == 20)
.collect(Collectors.toList());
System.out.println(peopleAge20);
// summary statics (average age) for all people
IntSummaryStatistics stats =
allPersons.stream().mapToInt(p -> p.getAge()).summaryStatistics();
System.out.printf("Average age: %f\n", stats.getAverage());
Note that this approach does break the idea of a Javabean, but that may or may not be an issue depending upon your requirements.
First thing, we should add a constructor to your Person class.
class Person {
public Person(String name, String title, int age) {
this.name = name;
this.title = title;
this.age = age;
}
}
Now while you read the input you can use a Map as follows. Here after reading each line, we create a Person object and then using that person's age we make an entry in the map with key as age and value as Person.
Map<Integer, Person> mapOfPeople = new HashMap<>();
while (input.hasNextLine()) {
String line[] = input.nextLine().split(",");
Perso person = new Perso(line[1], line[0], Integer.parseInt(line[2].trim()));
mapOfPeople.put(person.getAge(), person);
}
Now to fetch a particular Person by age just do
mapOfPeople.get(20);

Most efficient way to convert Enum values into comma seperated String

I have a java class in which I store an Enum.(shown at the bottom of this question) In this enum, I have a method named toCommaSeperatedString() who returns a comma separated String of the enums values. I am using a StringBuilder after reading some information on performance in this question here.
Is the way I am converting this enum's values into a commaSeperatedString the most efficient way of doing so, and if so, what would be the most efficient way to remove the extra comma at the last char of the String?
For example, my method returns 123, 456, however I would prefer 123, 456. If I wanted to return PROPERTY1, PROPERTY2 I could easily use Apache Commons library StringUtils.join(), however, I need to get one level lower by calling the getValue method when I am iterating through the String array.
public class TypeEnum {
public enum validTypes {
PROPERTY1("123"),
PROPERTY2("456");
private String value;
validTypes(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static boolean contains(String type) {
for (validTypes msgType : validTypes.values()) {
if (msgType.value.equals(type)) {
return true;
}
}
return false;
}
public static String toCommaSeperatedString() {
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for(validTypes msgType : validTypes.values()) {
commaSeperatedValidMsgTypes.append(msgType.getValue() + ", ");
}
return commaSeperatedValidMsgTypes.toString();
}
}
}
I wouldn't worry much about efficiency. It's simple enough to do this that it will be fast, provided you don't do it in a crazy way. If this is the most significant performance bottleneck in your code, I would be amazed.
I'd do it something like this:
return Arrays.stream(TypeEnum.values())
.map(t -> t.value)
.collect(Collectors.joining(','));
Cache it if you want; but that's probably not going to make a huge difference.
A common pattern for the trailing comma problem I see is something like
String[] values = {"A", "B", "C"};
boolean is_first = true;
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for(String value : values){
if(is_first){
is_first = false;
}
else{
commaSeperatedValidMsgTypes.append(',');
}
commaSeperatedValidMsgTypes.append(value);
}
System.out.println(commaSeperatedValidMsgTypes.toString());
which results in
A,B,C
Combining this with the answers about using a static block to initialize a static final field will probably give the best performance.
The most efficient code is code that doesn't run. This answer can't ever change, so run that code as you have it once when creating the enums. Take the hit once, return the calculated answer every other time somebody asks for it. The savings in doing that would be far greater in the long term over worrying about how specifically to construct the string, so use whatever is clearest to you (write code for humans to read).
For example:
public enum ValidTypes {
PROPERTY1("123"),
PROPERTY2("345");
private final static String asString = calculateString();
private final String value;
private static String calculateString() {
return // Do your work here.
}
ValidTypes(final String value) {
this.value = value;
}
public static String toCommaSeparatedString() {
return asString;
}
}
If you have to call this static method thousand and thousand of times on a short period, you may worry about performance and you should first check that this has a performance cost.
The JVM performs at runtime many optimizations.
So finally you could write more complex code without added value.
Anyway, the actual thing that you should do is storing the String returned by toCommaSeperatedString and returned the same instance.
Enum are constant values. So caching them is not a problem.
You could use a static initializer that values a static String field.
About the , character, just remove it after the loop.
public enum validTypes {
PROPERTY1("123"), PROPERTY2("456");
private static String valueSeparatedByComma;
static {
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for (validTypes msgType : validTypes.values()) {
commaSeperatedValidMsgTypes.append(msgType.getValue());
commaSeperatedValidMsgTypes.append(",");
}
commaSeperatedValidMsgTypes.deleteCharAt
(commaSeperatedValidMsgTypes.length()-1);
valueSeparatedByComma = commaSeperatedValidMsgTypes.toString();
}
public static String getvalueSeparatedByComma() {
return valueSeparatedByComma;
}
I usually add a static method on the enum class itself:
public enum Animal {
CAT, DOG, LION;
public static String possibleValues() {
return Arrays.stream(Animal.values())
.map(Enum::toString)
.collect(Collectors.joining(","));
}
}
So I can use it like String possibleValues = Animal.possibleValues();

How to make sure Uniqueness of Constants values in Java Class in development phase?

Our team have a shared Java class only for Constant values
When any developer need to add a constant
He will add a record in this class
public class Constants_Class {
public static final String Constant1 = "value1";
public static final String Constant2 = "value2";
public static final String Constant3 = "value3";
// Need to prevent that in Development time - NOT Run time
public static final String Constant4 = "value1"; // value inserted before
}
The problem is that
We need in Development time prevent any developer
To add a new constant its value inserted before
// Need Unique Constants Value(s)
Any suggestions ??
You really should be using enums. This will solve the problem you're seeing.
You can also associate String values with enums:
public enum MyEnums {
Constant1("value1"),
Constant2("value2"),
Constant3("value3");
private String value;
MyEnum(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}
Then you can do MyEnum.Constant1.getValue().
To do what you're asking at development time would require parsing the code, essentially duplicating compilation. So it makes sense to let it be compiled and create a unit test to perform your check, then set up the project so that unit test is run each time the code base is compiled. I'm pretty sure the most common unit test library in use is JUnit.
To easily check uniqueness of values, you can use the Set.add method, which returns false if the item being added already exists in the set:
#Test
public class TestConstantUniqueness() {
Set<String> stringValues = new HashSet<String>();
for (MyConstantEnum value : MyConstantEnum.values()) {
String s = value.stringValue();
Assert.assertTrue(
"More than one constant in " + MyConstantEnum.class
+ " has the string value \"" + s + "\"",
stringValues.add(s));
}
}

How do I maintain a pointer to a List in a Java class?

I have a very simple Java class:
public class Party {
private List<String> hosts = new ArrayList<String>();
private String headHost = null;
public void addHost(String name) {
hosts.add(name);
headHost = name;
}
}
But it seems a bit silly to maintain a String keeping track of the list's pointer...
1. Is there a better way for keeping track of who is the "head host"?
It won't always be the last person added, either:
public void setHost(int i) {
headHost = hosts.get(i); // potentially throws an exception based on i
}
public void setHost(String name) {
headHost = name;
}
2. What's the best way to change the current "head host"? Both of these methods could potentially take incorrect parameters.
The current version is just fine. If you are concerned about exceptions, you can apply some defensive programming to the code:
public void setHost(int i) {
if(i < 0 || i > hosts.size()-1){
throw new IllegalArgumentException("Index is out of range!");
}
headHost = hosts.get(i);
}
public void setHost(String name) {
if(!hosts.contains(name){
throw new IllegalArgumentException("The specified host does not exist.");
}
headHost = name;
}
List doesn't have a concept of current, at least not in Java. If you want to know what the first element is, just use List.get(0)
To get the last element, use hosts.get(hosts.size()-1).
You may also be interested in the Stack class, which has LIFO (last in, first out) methods to make it even easier to get the most recently entered element.
If for some reason you want to be able to lookup a host by String name, don't use a List, use a Map (preferably a HashMap)
You area already holding just a pointer. String is an object in java.
When you do this:
public void addHost(String name) {
hosts.add(name);
headHost = name;
}
There is only one string with two pointers to it, one pointer in the list and one in your instance variable headHost. There are not two copies of the actual data.

Trying to compare two objects and extract a third object containing their differences

I've got two domain objects, of the same type. They contain enums, primitive arrays, and other objects and theres a list in the Heirarchy there too.
I need something to extract a third object of the same type that only contains their differences, almost like a mask that contains only their changes. And anything that hasn't changed be set to null.
Everything points to the Apache BeanUtils, but I cant find exactly what I'm looking for, any suggestions?
Edit#1
Example to clarify :
If obj1 is the original, and obj2 is the updated version. Then if obj1.value is equal to obj2.value then obj3.value will be null. If obj1.value is not equal to obj2.value then obj3.value will be set to the value of obj2.value
Edit#2
Ideally it should be abstract and in no way need to know what type of object the comparison is being run on. As this could be used for different objects in the future.
If one of the update values is set to null than it can be ignored as if its not a change.
Your question is interesting for me. I searching very much for your goals and find a little library do it. This library is in google code and its name is jettison.
This utility has a main class with name Diff4J that has a method with diffs method and by it compare two object and find differents.
Then I write codes for your goals as following:
fisrt define a Model Object with name Bean :
public class Bean
{
private String name;
private String family;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getFamily()
{
return family;
}
public void setFamily(String family)
{
this.family = family;
}
public Bean()
{
}
public Bean(String name, String family )
{
this.name = name;
this.family = family;
}
}
Then coding a test class as following:
public static void main(String[] args) throws IllegalAccessException,
InvocationTargetException
{
Bean bean_1 = new Bean("Sara", "clooney");
Bean bean_2 = new Bean("Sally", "clooney");
Diff4J comparator = new Diff4J();
Collection<ChangeInfo> diffs = comparator.diff(bean_1, bean_2);
Bean final_result = new Bean();
for(ChangeInfo c : diffs)
{
String filedName = c.getFieldName();
Object to_value = c.getTo();
Object from_value = c.getFrom();
BeanUtilsBean.getInstance().setProperty(final_result, filedName, to_value);
}
System.out.println(final_result);
}
By this solution if you run this code see following result:
Bean [family=null, name=Sally]
this result is your goals.
Note: In last line of loop statement, I used BeanUtilBean from Apache Commons Util for fill object by Reflection.
This utility has a problem, it doesn't support Deep Comparator(maybe I couldn't find it) and you have to simulate this task.
for see this library go to http://code.google.com/p/jettison/.
I hope this answer help you.
It can be done without any external library ;)
Let's take a trivial bean
public class Bean {
public String value;
public List<String> list;
public String[] array;
public EnumType enum;
}
and add a static (factory) method:
public static Bean createDelta(Bean master, Bean variant) {
Bean delta = new Bean();
// fields are simple
if (!master.value.equals(variant.value))
delta.value = variant.value;
// enums are simple too
if (master.enumValue != variant.enumValue)
delta.value = variant.value;
// for arrays .. it get's slightly difficult, because arrays may vary in size
int size = master.array.length > variant.array.length ?
master.array.length : variant.array.length;
delta.array = new String[size];
for (int i = 0; i < size; i++) {
if ((i >= master.array.length) ||
(!master.array[i].equals(variant.array[i]))) {
delta.array[i] = variant.array[i];
// same pattern for lists - except we have to add null
int size = master.array.length > variant.array.length ?
master.array.length : variant.array.length;
delta.list = new ArrayList<String>();
for (int i = 0; i < size; i++) {
if ((i >= master.array.length) ||
(!master.array[i].equals(variant.array[i]))) {
delta.list.add(variant.get(i));
} else {
delta.list.add(null);
}
}
}
(Note - not tested, no IDE/compiler at hand - but it shows a general approach)

Categories