I have list of string data that are not change during any operation inside my program. But i need to access those data in several places by using key.
As a example: (1,ANN)(2,ALEX)(3,ANDROW)
Is there any way to store these data in separate class.Can I use java enum for this. thank you
With the use of enum you can implement something like below:
public enum Name {
ONE {
#Override
public String getName() {
return "ANN";
}
},
TWO {
#Override
public String getName() {
return "ALEX";
}
},
THREE {
#Override
public String getName() {
return "ANDROW";
}
};
public abstract String getName();
}
Then you can get the the names :
System.out.println(Name.ONE.getName());
This is really a good candidate for using Map. Where you can use your numbers as keys and String's as values.
https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
Map<Integer, String> map = new HashMap<Integer,String>();
Map<Integer,String> is one option and if key is also constant you could define string variable like
public static final string ONE = "ANN";
public static final string TWO = "ALEX";
A different way to use enums to define a statically mapping:
public enum Names {
ONE("ANN"),
TWO("ALEX"),
THREE("ANDREW");
private final String name;
private Names(String name){
this.name=name;
}
public String getName() {
return this.name;
}
}
This is only applicable to real-static values (change to values does mean a code change), but you can easily define multiple properties as well.
You can do the following:
import java.util.HashMap;
public class Main {
static HashMap<Integer,String>data = new HashMap<>();
public static void main(String[] args) {
// write your code here
data.put(data.size(),"ALEX"); // if you want 1-based indexing,
data.put(data.size(),"ANDROW"); // then use data.size()+1
data.put(data.size(),"ANN"); // instead of data.size()
for (int i = 0; i<data.size(); i++){
System.out.println(i+" : "+data.get(i)); // use i+1 if 1-based indexing
}
}
}
Related
I have created a simple class:
public class Example
{
private String name;
private int age;
// With getters and setters.
}
that I would like "put" into a chronicle map:
ChronicleMap<String,Example> map = ChronicleMapBuilder
.of(String.class, Example.class)
.name("example-map")
.entries(5_000)
.averageValue(new Example())
.valueMarshaller(ExampleSerializer.getInstance())
.averageKey("Horatio")
.createPersistedTo(new File("../logs/example.txt"));
However, I do not fully understand how to implement the ExampleSerializer class because I am not sure how the string member variables should be handled. How do I size strings? In the read and write methods, how do I read the string member variable, and how do I write the string member variable respectively. Pls note that on average, the name member string length will be between 7-10 characters. I have created the serializer below:
public class ExampleSerializer implements SizedReader<Example>,SizedWriter<Example>
{
private static ExampleSerializer INSTANCE = new ExampleSerializer();
public static ExampleSerializer getInstance() { return INSTANCE; }
private ExampleSerializer() {}
#NotNull
#Override
public Example read(Bytes in, long size, #Nullable Example using)
{
if (using == null)
using = new Example();
using.setAge(in.readInt());
using.setName(in.readUtf8()); // NOT SURE IF THIS IS CORRECT FOR A STRING
return using;
}
#Override
public long size(#NotNull Example toWrite)
{
return Integer.BYTES + ???; // NOT SURE WHAT THE SIZE SHOULD BE FOR STRING MEMBER?
}
#Override
public void write(Bytes out, long size, #NotNull Example toWrite)
{
out.writeInt(toWrite.getAge());
out.writeUtf8(toWrite.getName()); // NOT SURE IF THIS IS CORRECT FOR A STRING
}
}
Yes, I read many examples in web, but I didn't find a way how to call a method based on string value. May be I am not searching in right way... I wrote all code, but don't know how to call the method.
fyi: I don't want to use if else or switch case
Here is what I want:
I get the card reader type as String from database. I have to call the corresponding class' method.
My code:
LoginPanel.java
public class LoginPanel {
public static void main(String args[]) {
String readerType = "Omnikey5427-CK"; // I get this ("Omnikey5427-CK" or "Omnikey5427-G2") from a database as String
// I WANT TO CALL getCardNumber() method of respective class
}
}
ISmartCardReader.java
public interface ISmartCardReader {
public Integer getCardNumber();
}
Omnikey5427G2.java
public class Omnikey5427G2 implements ISmartCardReader {
public Omnikey5427G2() {
System.out.println("G222222222222222...");
}
public Integer getCardNumber() {
return 222;
}
}
Omnikey5427CK.java
public class Omnikey5427CK implements ISmartCardReader {
public Omnikey5427CK() {
System.out.println("CKKKKKKKKKKKKKKK...");
}
public Integer getCardNumber() {
return 111;
}
}
SmacrtCardEnumFactory.java
public enum SmacrtCardEnumFactory {
OMNIKEY5427CK("Omnikey5427-CK") {
public ISmartCardReader geInstance() {
return new Omnikey5427CK();
}
},
OMNIKEY5427G2("Omnikey5427-G2") {
public ISmartCardReader geInstance() {
return new Omnikey5427G2();
}
};
private String cardReaderName;
private SmacrtCardEnumFactory(String cardReaderName) {
this.cardReaderName = cardReaderName;
}
public String cardReaderName() {
return cardReaderName;
}
}
You can use valueOf() function of enum provided your enum sonstant names match strings used to lookup (you may use cardName.toUpper()). You may also create objects for all the card types and store them in a hash map and then lookup them. You can also write some fatory method, but this will be if-then-else or switch inside
You could iterate over the factory's values() and get the one that matches the string:
public enum SmacrtCardEnumFactory {
// current code omitted for brevity
public static getSmartCardReader(String name) {
return Arrays.stream(values())
.filter(r -> r.cardReaderName().equals(name))
.map(SmacrtCardEnumFactory::getInstance();
.orElse(null);
}
}
I have a list of objects "SaleItem". they are all objects of the same class. each object has a String field "name" and an int field "value". I want to see if one of the objects contains a name. It seems that I can't use the "contains" method to do this. I see two solutions. one is to iterate through all the objects to check if one has said name:
for (SaleItem item: myList) {
if (item.getName() == "banana") {
// do stuff
}
}
The other solution would be to create a new list of Strings from "myList" and use the contains method on that:
ArrayList<String> nameList = new ArrayList<>();
for (SaleItem item: myList) {
nameList.add(item.getName());
}
if (nameList.contains("banana")) {
// do stuff
}
I imagine the first method would be most efficient if I'm only doing it once, and the second would be more efficient if I'm doing it many times. Being a bit of a newbie without a formal education, I don't know what's proper in this situation.
Since SaleItem.getName() returns a string, you should be able to use "contains" method.
It seems like you have initialized the ArrayList or the SaleItem object incorrectly.
public class TestApp {
public static void main(String[] args) {
List<SaleItem> list = new ArrayList<SaleItem>();
SaleItem s1 = new SaleItem();
s1.setName("banana");
s1.setValue(1);
SaleItem s2 = new SaleItem();
s2.setName("apple");
s2.setValue(2);
list.add(s1);
list.add(s2);
for (SaleItem item: list) {
if (item.getName().contains("banana")) {
System.out.println("Pass");
}
}
}
}
class SaleItem {
private String name;
private int value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Try with this code
public class SaleItem {
private String itemName;
public String getItemName() {
return itemName;
}
public SaleItem setItemName(String itemName) {
this.itemName = itemName;
return this;
}
#Override
public String toString() {
return "[SaleItem : { itemName = " + this.getItemName() + " }]";
}
public static void main(String[] args) {
ArrayList<SaleItem> nameList = new ArrayList<>();
nameList.add(new SaleItem().setItemName("banana"));
nameList.add(new SaleItem().setItemName("grape"));
nameList.add(new SaleItem().setItemName("watermelon"));
nameList.add(new SaleItem().setItemName("orange"));
nameList.add(new SaleItem().setItemName("guava"));
for (SaleItem item : nameList) {
if (item.toString().contains("banana")) {
// Do this
}
}
}
}
A List's .contains method isn't magical, it will generally just loop through the elements checking for equality, O(n) linear performance.
Your first solution is probably fine.
If you really did expect repeated access and wanted better than linear performance on subsequent lookups, you'd probably want to construct a Map<String,SaleItem>, or a Set<String> depending on what you wanted to do with it. But those solutions would normally only work on exact matches. Once you need case-insensitive matches, they have to be TreeMap or TreeSet with a case-insensitive comparator. And if you want partial matching (like using String.contains() or a regular expression), you'd want to go back to a linear search.
But don't do any of that unless you have to. Keep it simple.
I have a number of setter methods which take an enum. These are based on incoming objects attribute. Rather than write a bunch of these is there a way around having to hard code say 10 different case statements. Would there be a way to create a reusable method?
//Side class declared as
public final enum Side
//How I initialise side
static Side side = Side.SELL;//default
//method to set object
Obj.setSide(sideEnum(zasAlloc.getM_buySellCode()));
//How I am implementing it
public static Side sideEnum(String buysell)
{
if(buysell.equalsIgnoreCase("S"))
{
side = Side.SELL; //default
}
else if(buysell.equalsIgnoreCase("B"))
{
side = Side.BUY;
}
return side;
}
You can implement that functionality in your Enum.
public enum Side {
BUY("B"), SELL("S"), ...
private String letter;
private Side(String letter) {
this.letter = letter;
}
public static Side fromLetter(String letter) {
for (side s : values() ){
if (s.letter.equals(letter)) return s;
}
return null;
}
}
You could also do this as a helper static method if you can't edit Side.
public static Side fromString(String from) {
for (Side s: Side.values()) {
if (s.toString().startsWith(from)) {
return s;
}
}
throw new IllegalArgumentException( from );
}
The above method assumes your strings correspond to the names of you enums.
Enums have valueOf() method that can be used to convert from String. Is it what you are looking for?
I ended up using a simple object map:
private static HashMap<String, Side> sideMap = new HashMap<String, Side>(7);
static{
sideMap.put("B", Side.BUY);
sideMap.put("S", Side.SELL);
}
and simply using
Obj.setSide(sideMap.get(zasAlloc.getM_buySellCode()));
I think you need smth like:
Obj.setSide(Side.valueOf(zasAlloc.getM_buySellCode()));
I am creating a helper class in parsing XML elements, so the developer do not need to know the exact name and capitalization of the XML fields.
private static class TagNames{
public static String RESOURCE_ID = "ResourceId";
public static String RESOURCE_NAME = "ResourceName";
public static String RESOURCE_PRICE = "ResourcePrice";
}
This makes it easier to do things like:
someXMLParser.getValueByTagName(TagNames.RESOURCE_ID);
My question is this. If I want to iterate over all the fields declared in class TagNames, how do I do that? Pseudocode:
For tag in TagNames:
someXMLParser.getValueByTagName(tag)
I know I will probably have to restructure all of this. But I can't figure out a way to make the names easily accessible as well as iterable, without any duplication.
Any suggestions?
You're literally asking for a solution based on reflection, but I think a Java Enum may be a better choice in this case. Building on Frederick's example:
public class EnumTest {
public enum Tags {
RESOURCE_ID("ResourceId"),
REOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice");
private final String tagName;
Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
public static void main(String[] args) {
for(Tags tag : Tags.values()) {
System.out.println("const:" + tag.name()
+ " tagName:" + tag.getTagName());
}
// API user might do e.g.:
// document.getValueForTag(Tags.REOURCE_NAME);
}
}
Although I agree that you should probably use enums or ResourceBundles, here's a solution to your actual question. A method that generates a Map name -> value from all public constants in a given class (the only thing that's missing should be try / catch or throws)
public static Map<String, Object> getConstantValues(Class<?> clazz){
Map<String, Object> constantValues = new LinkedHashMap<String, Object>();
for(Field field : clazz.getDeclaredFields()){
int modifiers = field.getModifiers();
if(Modifiers.isPublic(mod)
&& Modifiers.isStatic(mod) && Modifiers.isFinal(mod)){
constantValues.put(field.getName(), field.get(null));
}
}
return constantValues;
}
You may want to consider using a ResourceBundle instead of a class to store the tag names. May require a little bit of reworking of your code but it will be easier to produce a list of tags compared to what you are doing now, and adding a new tag won't require much work other then adding a line to the properties file.
You can do this quite easily using enum and an accompanying array:
public class Main {
public enum TagName { RESOURCE_ID, REOURCE_NAME, RESOURCE_PRICE }
private static String[] tags = {"ResourceID", "ResourceName", "ResourcePrice"};
public static String getValueByTagName(TagName tag) {
return tags[tag.ordinal()];
}
public static void main(String[] args) {
System.out.println("Calling by getValueByTagName:");
System.out.println(getValueByTagName(TagName.RESOURCE_ID));
System.out.println("Calling TagName.values() for loop:");
for (TagName t : TagName.values()) {
System.out.println(getValueByTagName(t));
}
}
}
Using an enum is a good fit, especially if you use a custom constructor and the built in "values" method:
public class Main {
public static enum TagName {
RESOURCE_ID("ResourceId"),
RESOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice"),
;
private String s;
private TagName(String s) { this.s = s; }
public String toString() { return this.s; }
public static String[] strings() {
List<String> ss = new ArrayList<String>();
for (TagName tagName : TagName.values()) {
ss.add(tagName.toString());
}
return ss.toArray(new String[ss.size()]);
}
}
public static void main(String[] args) {
// Use TagName.values() for the enums, or for strings...
for (String s : TagName.strings()) {
System.out.println(s);
}
}
}
This way you can simply add new tags and they'll automatically get picked up by the "strings" method; for extra performance you could compute that string array just once, statically, since you can't change the set of enums dynamically. You could get even fancier by auto-generating the tag strings from their constant values, if they are really normalized...