Setter for a key value pair List object - java

I am stumped with this one and hoping to see if this could be a good way to solve my issue.
I'll first explain how the program works.
I have a class that is simply a key value pair:
public class KeyValuePair {
private final String name;
private final String value;
public KeyValuePair(String n, String v) {
name = n;
value = v;
}
I have another class called List that uses the key value pair.
public class myList {
private List<KeyValuePair> myList = new ArrayList<KeyValuePair>();
public myList(List<KeyValuePair> nvp) {
List = nvp;
}
public List<KeyValuePair> getList() {
return myList;
}
}
So in my program i then create an List object and populate it with the key value pairs and review a new List(kvp).
public myList pullData(){
Final myList<KeyValuePair> nvp = new ArrayList<KeyValuePair>();
List<String[]> results = getResults()
for(String[] str : results)
{
KeyValuePair kvp = new KeyValuePair(str[0], str[1]);
nvp.add(kvp)
}
}
return new myList(nvp)
}
now I have run into the situation where I need to update the value of each pair. The key stays the same.
Originally I had created a newList object and populated with the updated Value for the key pair, but then though there should be a better method, perhaps creating an update or a setter method within the List object to do this.
Which would be better creating a new object, or updating? I would think updating the value in the key value pair, however, I am not sure how to do this.
Any help or suggestions would be greatly appreciated.

Then you can set the keys and values if you want:
public class KeyValuePair {
private String name;
private String value;
public KeyValuePair(String n, String v) {
name = n;
value = v;
}
public String getName(){
return name;
}
public String getValue(){
return value;
}
public void setName(String n){
name = n;
}
public void setValue(String v){
value = v;
}
}
However a list of these is never going to be as useful as a map that is already there in Java.

Lose final modifier and create nice getters and setters for your fields
public class KeyValuePair {
private String name;
private String value;
public KeyValuePair(String n, String v) {
name = n;
value = v;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
and then you can e.g. add plus sign to your values:
public void update(List<KeyValuePair> pairs) {
for (KeyValuePair kvp: pairs) {
kvp.setValue(kvp.getValue() + "+");
}
}

Simply by adding a setter to my key value pair class resolved this issue. Not too sure why i didn't see that before, for some reason I thought I needed to do it in myList class.
public void setValue (String newValue){
value = newValue;
}

Related

ArrayLists and returning null

I'm trying finish my method 'priority' which should return the priority of the Task. and make it return null if the specified name does not exist (as shown in the main). I've tried iterating through the ArrayList, but i don't think this is the way to do it. Is there anyone who can help me out?
class Task
{
public static final ArrayList<Task> ALL_TASKS = new ArrayList<>();
private String name;
private Integer priority;
public Task(String name, Integer priority)
{
this.name = name;
this.priority = priority;
ALL_TASKS.add(this);
}
#Override public String toString()
{
return "name: " + this.name + "\tpriority: " + this.priority;
}
}
class Main
{
public static void main(String[] arguments)
{
new Task("Clean", 5);
new Task("Dishwash", 4);
new Task("Study", 1);
System.out.println(Task.priority("Dishwash"));
System.out.println(Task.priority("Vacuumclean"));
}
}
Try this:
public static Integer priority(String name) {
for(Task task : ALL_TASKS) {
if(task.name.equals(name)) {
return task.priority;
}
}
return null;
}
Or using Stream-API:
public static Integer priority(String name) {
return ALL_TASKS.stream()
.filter(task -> task.name.equals(name))
.map(task -> task.priority)
.findFirst()
.orElse(null);
}
public static Integer priority(String name) {
for(int i = 0; i < ALL_TASKS.size(); i++){
if(ALL_TASKS.get(i).getName().equals(name))
return ALL_TASKS.get(i).getPriority();
else
return null; // but if using Java 8 Option<Task> would be better
}
}
This is the example which I would use. It is not tested but it give you idea what create and the way of thinking.
Also in my solution I assume you also create getName() and getPriority() methods for your Task
The Java Stream API provides a more convenient and efficient approach to iterating and processing elements of a collection.
class Task
{
public static final ArrayList<Task> ALL_TASKS = new ArrayList<>();
public static Integer priority(String name)
{
List<Task> result = ALL_TASKS.stream().filter(task->
(task.name.equals(name))).collect(Collectors.toList());
if(result.isEmpty())
{
return null;
}
else
{
return result.get(0).priority;
}
}
private String name;
private Integer priority;
public Task(String name, Integer priority)
{
ALL_TASKS.add(this);
this.name = name;
this.priority = priority;
}
public String toString()
{
return "name: " + this.name + "\tpriority: " + this.priority;
}
}
class Main
{
public static void main(String[] arguments)
{
new Task("Clean", 5);
new Task("Dishwash", 4);
new Task("Study", 1);
System.out.println(Task.priority("Dishwash"));
System.out.println(Task.priority("Vacuumclean"));
}
}
An option would be storing your List as a Map instead, using the tasks name as the key
HashMap<String, Task> ALL_TASKS = new HashMap<>();
Task task = ALL_TASKS.get(codeIsIn);
if(task!=null)
{
Integer priority = task.priority;
}
If a Task consists only of name and priority, it gets even simpler
HashMap<String, Integer> ALL_TASKS = new HashMap<>();
Integer priority = ALL_TASKS.get(codeIsIn);
//null if nonexistent

Return object from a list as CustomObject not just raw <T> Object

I have a CustomObject declared as raw type of <T>. And when I populate a List<CustomObject> with new instances of it, I can't get them back as a CustomObject, only as an Object.
public class CustomObject<T> {
private String name;
private T value;
// getters and setters
}
But obviously when I use subclass, all is working as expecting;
public class CustomObject {
private class SubCustomObject<T> {
private String name;
private T value;
}
public CustomObject() {
this.customObject = new SubCustomObject();
private SubCustomObject customObject;
// getters and setters
}
Is there a way to make the first example to behave like the second one, and avoid using extra object and so I could do this:
public class CustomObject<T> {
private String name;
private T value;
private boolean isGroup;
// getters and setters
private void setValue(T value) {
if (value instanceof String) {
this.value = value;
this.isGroup = false;
}
if (value instanceof CustomObject) {
if (isGroup()) {
((List<CustomObject>) this.value).add((CustomObject) value);
} else {
this.value = (T) new ArrayList<CustomObject>();
this.isGroup = true;
setValue(value);
}
}
}
}
public void getItemByName(String name) {
// say the list is already populated
for (CustomObject object : listOfCustomObject) {
String nameField = object.getName();
if (name.equals(nameField) {
System.out.println(nameField);
}
}
}
Instead of this one:
public void getItemByName(String name) {
// say the list is already populated
for (Object object : listOfCustomObject) {
String nameField = ((CustomObject)object).getName();
if (name.equals(nameField) {
System.out.println(nameField);
}
}
}
// Apply that behavior to this and avoid to use inner class.
public class MetadataEntry {
public MetadataEntry() {
this.entity = new Entry();
}
private class Entry<T> {
private String name;
private T value;
private boolean isGroup;
private void setValue(T value) {
if (value instanceof String) {
this.value = value;
this.isGroup = false;
}
if (value instanceof MetadataEntry) {
if (isGroup()) {
((List<MetadataEntry>) this.value).add((MetadataEntry) value);
} else {
this.value = (T) new ArrayList<MetadataEntry>();
this.isGroup = true;
setValue(value);
}
}
}
}
private Entry entity;
public void setName(String name) {
this.entity.name = name;
}
public String getName() {
return this.entity.name;
}
public void setValue(String value) {
entity.setValue(value);
}
public void setValue(MetadataEntry value) {
entity.setValue(value);
}
public boolean isGroup() {
return this.entity.isGroup;
}
public List<MetadataEntity> getChildNodes() {
if (isGroup()) {
return (List<MetadataEntry>) this.entity.value;
}
return null;
}
public String getValue() {
if (!isGroup()) {
return (String) this.entity.value;
}
return null;
}
}
You can not make a list of different types X,Y,Z and put it in a single container of type W. You need to define a bounding parameter on your raw type so that your items and list are of same type. probably your T should be bounded by some interface type or it should extends some class.
Here’s my suggestion. I have abandoned the generics. Instead of just one inner class there is now an abstract inner class with two subclasses, one for groups and one for entries that are not groups. The good news: no cast is necessary anywhere.
public class MetadataEntry {
private String name;
static abstract class Entry {
abstract Entry setValue(String value);
abstract Entry setValue(MetadataEntry value);
abstract boolean isGroup();
abstract List<MetadataEntry> getChildNodes();
abstract String getSimpleValue();
}
static class SimpleEntry extends Entry {
private String value;
public SimpleEntry(String value) {
this.value = value;
}
#Override
Entry setValue(String value) {
this.value = value;
return this;
}
#Override
Entry setValue(MetadataEntry value) {
return new GroupEntry(value);
}
#Override
public boolean isGroup() {
return false;
}
#Override
public List<MetadataEntry> getChildNodes() {
return null;
}
#Override
public String getSimpleValue() {
return value;
}
}
static class GroupEntry extends Entry {
List<MetadataEntry> value;
public GroupEntry(MetadataEntry value) {
this.value = new ArrayList<>();
this.value.add(value);
}
#Override
Entry setValue(String value) {
return new SimpleEntry(value);
}
#Override
Entry setValue(MetadataEntry value) {
this.value.add(value);
return this;
}
#Override
public boolean isGroup() {
return true;
}
#Override
public List<MetadataEntry> getChildNodes() {
return value;
}
#Override
public String getSimpleValue() {
return null;
}
}
private Entry entity;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setValue(String value) {
entity = entity.setValue(value);
}
public void setValue(MetadataEntry value) {
entity = entity.setValue(value);
}
public boolean isGroup() {
return this.entity.isGroup();
}
public List<MetadataEntry> getChildNodes() {
return entity.getChildNodes();
}
public String getValue() {
return entity.getSimpleValue();
}
}
I have used an idea similar to what m 1987 said about a class that returns an instance of itself. I applied it to the inner classes only to free the users of the outer class from caring about this trickery. If you prefer, I am sure it could be applied to the outer class instead. Then you would have an abstrat class on the outer level with two subclasses, and would no longer need the inner classes. This is one of the things you asked for, so you may prefer it, but it comes at a cost: anyone calling setValue() on the outer class would need to remember that they got a new instance back.
I have a CustomObject declared as raw type of <T>.
That doesn't makes sense. You either have a raw type or a generic, not a raw type of a generic.
And when I populate a List with new instances of it, I can't get them back as a CustomObject, only as an Object.
Because your list is not generic (always bad). When you declare a List<Something> it will return Something on a get call. That Something can be generic or a raw type. A List<CustomObject<String>> will not accept a CustomObject<Integer> and using the raw type List<CustomObject> will end in disaster, hence the danger in raw types.
Now let's look at your code. The class
public class CustomObject<T> {
private String name;
private T value;
}
defines an object that behaves the same for any type. In essence what you have here is just a glorified Object with a String serving as its name attached to it.
However, now you do
private void setValue(T value) {
if (value instanceof String)
// ...
if (value instanceof CustomObject)
// ...
}
which separates the behavior for different types. and what happens if the generic type is not a String or a CustomObject?
Let's try to solve your problem. Since generics are meant to unify the behavior, let's look at what the unified behavior is that you're trying to get:
public void getItemByName(String name) {
for (CustomObject object : listOfCustomObject) {
String nameField = object.getName();
// ...
}
}
}
Basically, you require that all the items in listOfCustomObject implement a String getName() method. That's it as far as I can see from your question. That means that your CustomObject<T> should either implement an interface or extend a class (call it Superthing) with that method. Then you will just declare your list as List<? extends Superthing>.
As for the CustomObject itself, it doesn't need to be generic as you hint that there are only 2 types of generics you want to deal with (you have 2 ifs, but no else to deal with a general case). It looks like what you want are 2 different classes with different behaviors that both implement or extend a common supertype.
Try something like this:
abstract class AbstractEntry {
private String name;
protected boolean isGroup;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isGroup() {
return isGroup;
}
}
class MetaEntry extends AbstractEntry {
AbstractEntry value;
MetaEntry(AbstractEntry value) {
this.value = value;
// handle isGroup
}
public void setValue(AbstractEntry value) {
this.value = value;
}
public AbstractEntry getValue() {
if (!isGroup)
return value;
return null;
}
}
class StringEntry extends AbstractEntry {
String value;
StringEntry(String value) {
this.value = value;
isGroup = false;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
I think there is no need of list as it always hold only one element. As #Ole V.V mentioned, the requirement naturally calls for the use of composition and in fact, generic does not fit into your requirements. Here is how I would tackle your requirements:
public interface Named {
public String getName();
public String getValue();
}
public class CustomObject implements Named {
private String name;
private String value;
private boolean isGroup;
// getters and setters
private boolean isGroup() {
return isGroup;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class CustomObject2 implements Named {
private String name;
private CustomObject value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value.getValue();
}
public void setValue(CustomObject value) {
this.value = value;
}
}
public class DriverCustomObject {
public static void main(String arg[]) {
CustomObject t = new CustomObject();
t.setName("key1");
t.setValue("value1");
CustomObject2 t2 = new CustomObject2();
t2.setName("complex");
t2.setValue(t);
List<Named> list = new ArrayList<Named>();
list.add(t);
list.add(t2);
for (Named l : list) {
System.out.println(l.getName());
System.out.println(l.getValue());
}
}
}

how to Externalise Java enums with Attributes into XML

i have a Java Enum like below
public enum TestEnum{
{
A("a","b","c"),
B("a1","b1","c1"),
C("a2","b2","c2");
TestEnum(String a,String b,String c){
}
private String a;
private String b;
private String c;
}
I want to externalize this config to an XML file but XSDs donot seem to support attributes on Enum Element type. Is there a way to work this around or an alternate to it.
You could do something like this (even though for enum, this looks too verbose)
#XmlJavaTypeAdapter(CountXmlAdapter.class)
public enum Count {
ONE(1, "one"),
TWO(2, "two"),
THREE(3, "three");
private final int index;
private final String name;
private Count(int index, String name) {
this.index = index;
this.name = name;
}
#XmlAccessorType(XmlAccessType.FIELD)
public static class CountWrapper {
private int index;
private String name;
public CountWrapper() {
}
public CountWrapper(int index, String name) {
this.index = index;
this.name = name;
}
}
public static class CountXmlAdapter extends XmlAdapter<CountWrapper, Count> {
#Override
public Count unmarshal(CountWrapper v) throws Exception {
return v != null ? Count.valueOf(v.name.toUpperCase()) : null;
}
#Override
public CountWrapper marshal(Count v) throws Exception {
return v != null ? new CountWrapper(v.index, v.name) : null;
}
}
}

Throws Exception while instantiating class

I have a very simple problem-
I have a class named DEClient whose constructor is like this-
public DEClient(List<DEKey> keys) {
process(keys);
}
And DEKey class is like this-
public class DEKey {
private String name;
private String value;
public DEKey(){
name = null;
value = null;
}
public DEKey(String name, String value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Now I am trying to instantiate DEClient constructor. So for that I need to have List<DEKey>.
So what I did is I instantiated DEKey class like below using service.getKeys() (which will return String) and id as the value.
DEKey dk = new DEKey(service.getKeys(), id);
//The below line throws exception whenever I am running.
DEClient deClient = new DEClient((List<DEKey>) dk);
What wrong I am doing here?
You need to first make a List, then add your key to that List. Casting like you have done is not the way to do it, since DEKey is not a List and casting into it will throw a ClassCastException.
DEKey dk = new DEKey(service.getKeys(), id);
List<DEKey> list = new ArrayList<DEKey>();
list.add (dk);
DEClient deClient = new DEClient(list);

Java getting the Enum name given the Enum Value

How can I get the name of a Java Enum type given its value?
I have the following code which works for a particular Enum type, can I make it more generic?
public enum Category {
APPLE("3"),
ORANGE("1"),
private final String identifier;
private Category(String identifier) {
this.identifier = identifier;
}
public String toString() {
return identifier;
}
public static String getEnumNameForValue(Object value){
Category[] values = Category.values();
String enumValue = null;
for(Category eachValue : values) {
enumValue = eachValue.toString();
if (enumValue.equalsIgnoreCase(value)) {
return eachValue.name();
}
}
return enumValue;
}
}
You should replace your getEnumNameForValue by a call to the name() method.
Try below code
public enum SalaryHeadMasterEnum {
BASIC_PAY("basic pay"),
MEDICAL_ALLOWANCE("Medical Allowance");
private String name;
private SalaryHeadMasterEnum(String stringVal) {
name=stringVal;
}
public String toString(){
return name;
}
public static String getEnumByString(String code){
for(SalaryHeadMasterEnum e : SalaryHeadMasterEnum.values()){
if(e.name.equals(code)) return e.name();
}
return null;
}
}
Now you can use below code to retrieve the Enum by Value
SalaryHeadMasterEnum.getEnumByString("Basic Pay")
Use Below code to get ENUM as String
SalaryHeadMasterEnum.BASIC_PAY.name()
Use below code to get string Value for enum
SalaryHeadMasterEnum.BASIC_PAY.toString()
Try, the following code..
#Override
public String toString() {
return this.name();
}
Here is the below code, it will return the Enum name from Enum value.
public enum Test {
PLUS("Plus One"), MINUS("MinusTwo"), TIMES("MultiplyByFour"), DIVIDE(
"DivideByZero");
private String operationName;
private Test(final String operationName) {
setOperationName(operationName);
}
public String getOperationName() {
return operationName;
}
public void setOperationName(final String operationName) {
this.operationName = operationName;
}
public static Test getOperationName(final String operationName) {
for (Test oprname : Test.values()) {
if (operationName.equals(oprname.toString())) {
return oprname;
}
}
return null;
}
#Override
public String toString() {
return operationName;
}
}
public class Main {
public static void main(String[] args) {
Test test = Test.getOperationName("Plus One");
switch (test) {
case PLUS:
System.out.println("Plus.....");
break;
case MINUS:
System.out.println("Minus.....");
break;
default:
System.out.println("Nothing..");
break;
}
}
}
In such cases, you can convert the values of enum to a List and stream through it.
Something like below examples. I would recommend using filter().
Using ForEach:
List<Category> category = Arrays.asList(Category.values());
category.stream().forEach(eachCategory -> {
if(eachCategory.toString().equals("3")){
String name = eachCategory.name();
}
});
Or, using Filter:
When you want to find with code:
List<Category> categoryList = Arrays.asList(Category.values());
Category category = categoryList.stream().filter(eachCategory -> eachCategory.toString().equals("3")).findAny().orElse(null);
System.out.println(category.toString() + " " + category.name());
When you want to find with name:
List<Category> categoryList = Arrays.asList(Category.values());
Category category = categoryList.stream().filter(eachCategory -> eachCategory.name().equals("Apple")).findAny().orElse(null);
System.out.println(category.toString() + " " + category.name());
Hope it helps! I know this is a very old post, but someone can get help.
I believe it's better to provide the required method in the enum itself. This is how I fetch Enum Name for a given value. This works for CONSTANT("value") type of enums.
public enum WalletType {
UPI("upi-paymode"),
PAYTM("paytm-paymode"),
GPAY("google-pay");
private String walletType;
WalletType(String walletType) {
this.walletType = walletType;
}
public String getWalletType() {
return walletTypeValue;
}
public WalletType getByValue(String value) {
return Arrays.stream(WalletType.values()).filter(wallet -> wallet.getWalletType().equalsIgnoreCase(value)).findFirst().get();
}
}
e.g. WalletType.getByValue("google-pay").name()
this will give you - GPAY
enum MyEnum {
ENUM_A("A"),
ENUM_B("B");
private String name;
private static final Map<String,MyEnum> unmodifiableMap;
MyEnum (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
static {
Map<String,MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
for (MyEnum instance : MyEnum.values()) {
map.put(instance.getName().toLowerCase(),instance);
}
unmodifiableMap = Collections.unmodifiableMap(map);
}
public static MyEnum get (String name) {
return unmodifiableMap.get(name.toLowerCase());
}
}
Now you can use below code to retrieve the Enum by Value
MyEnum.get("A");

Categories