As you can see below, I have three declared enums, and each class has a method called getEnumByName() which revives a name and returns the enum which has that name.
I have noticed that I am duplicating the same functionality of this method on each enum.
Is there any way to change this method to a generic one, which receives the given enum's type and does the same logic?
public class Enums {
public enum A {
APPLY("Apply", "abcde");
private String id;
private String name;
A(String name, String id) {
this.name = name;
this.id = id;
}
public static A getEnumByName(String name) throws Exception {
for (A instance : A.values()) {
if (instance.getName().equals(name)) return instance;
}
throw new Exception("There is no operations matches :" + name);
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
public enum B {
APPLY("Apply", "1"),
SAVE("Save", "2"),
REVERT("Revert", "2"),
REVERT_CHILD("Revert->Revert", "4"),
REVERT_APPLY("Revert->Revert Apply", "5"),
SYNC("Sync", "6"),
OPERATIONS("Operations", "7"),
IMPORT("Import", "8"),
EXPORT("Export", "9"),
DIFF("Diff", "10");
private String id;
private String name;
B(String name, String id) {
this.name = name;
this.id = id;
}
public static B getEnumByName(String name) throws Exception {
for (B instance : B.values()) {
if (instance.getName().equals(name)) return instance;
}
throw new Exception("There is no operations matches :" + name);
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
public enum C {
UPDATE_POLICES("Update Policies", "A"),
OPERATIONS("Operations", "B"),
IMPORT_CONFIGURATION_FILE("Import Configuration File", "c"),
EXPORT_CONFIGURATION_FILE("Export Configuration File", "d"),
EXPORT_LOG_SUPPORT_FILE("Export Log Support File", "f"),
EXPORT_TECHNICAL_SUPPORT_FILE("Export Technical Support File", "g"),
UPDATE_SOFTWARE_VERSION("Update Software Version", "g"),
UPDATE_SECURITY_SINGAUTES("Update Security Signatures", "h"),
DIFF("Diff", "k");
private String id;
private String name;
C(String name, String id) {
this.name = name;
this.id = id;
}
public static C getEnumByName(String name) throws Exception {
for (C instance : C.values()) {
if (instance.getName().equals(name)) return instance;
}
throw new Exception("There is no operations matches :" + name);
}
public String getName() {
return name;
}
public String getId() {
return id;
}
}
}
One option is to have them all implement a common interface called, say, Named:
interface Named {
String getName();
}
Now you can create a generic method like this:
static <E extends Enum<E> & Named> E getEnumByName(Class<E> enumClass, String name) throws Exception {
return Arrays.stream(enumClass.getEnumConstants())
.filter(e -> e.getName().equals(name))
.findAny()
.orElseThrow(() -> new Exception("There is no operations matches :" + name));
}
And call it like this:
A a = getEnumByName(A.class, "Apply");
Consider using the static Enum valueOf() method. You can call it generically as follows or just call it directly. See this answer for details.
static <E extends Enum<E>> E getEnumByName(Class<E> enumClass, String name) {
return Enum.valueOf(enumClass, name);
}
Related
I just start to learn java recently, i got 1 problem about the validation for setter, refer below is the setter validation for string type , what should i should i write to do the setter validation for boolean and double? below is the code i wrote for string.
public class Person
{
private String name;
private String id;
private boolean isNew;
private double bonus
public Person()
{
this("Unknown","unknown",true,0.0);
}
public Person(String id,String name,boolean isNew,double bonus)
{
setId(id);
setName(name);
setIsNew(isNew);
setBonus(bonus);
}
public getId()
{
return id;
}
public getName()
{
return name;
}
public setId()
{
this.id = id;
}
public setName()
{
this.name = name;
}
public void display()
{
System.out.println("Id:" + id);
System.out.printoutln("Name:" + name);
}
// setter validation for string
public void setName(String name)
{
if(name == null)
{
throw new IllegalArgumentException("A valid name must be provided ");
}
name = name.trim();
if(name.length() ==0)
{
throw new IllegalArgumentException("Name must not be blank ");
}
this.name = name;
}
// setter validation for id
public void setId(String id)
{
if(id == null)
{
throw new IllegalArgumentException("A valid id must be provided ");
}
id = id.trim();
if(id.length() ==0)
{
throw new IllegalArgumentException("Id must not be blank ");
}
this.id = id;
}
}
I just start to learn java recently, i got 1 problem about the validation for setter, refer below is the setter validation for string type , what should i should i write to do the setter validation for boolean and double?
When you want return value you have to declare returned type for example "public String getId()" instead "public getId()".
Setter expects a parameter. Example: "public setId(String id)".
All args constructor should looks like:
public Person(String name, String id, boolean isNew, double bonus) {this.name = name; this.id = id;this.isNew = is;this.bonus = bonus; }
For boolean argument constructor expect value. If you want validate something you can change type to Boolean and handle NullPointerExeption.
Or create custom exception:
public class MyWrongBooleanException extends RuntimeException
{
public IncorrectFileExtensionException(String errorMessage, Throwable err)
{
super(errorMessage, err);
}
}
I've built a client-server application, with working connection setup and handling. I would like the client to send requests of different types, each with unique fields but all of which inheriting from a "Request" superclass. Is there a way to do this?
For example I have a Foo class that implements serializable
class Foo implements Serializable{
public String name;
public Foo() {
this.name = "Default";
}
public Foo(String name) {
this.name = name;
}
}
and two subclasses that extend it
class BarOne extends Foo {
public String name;
public int id;
public Bar(String name, int id) {
super(name);
this.id = id;
}
}
class BarTwo extends Foo {
public String name;
public String lastName;
public Bar(String name, String lastName) {
super(name);
this.lastName = lastName;
}
}
Is there a way to have the client send instances of BarOne and BarTwo through an ObjectOutputStream and have the server figure out whether what it receives is an intance of one or the other?
There is no restriction here, you can serialize a subclass without difficulties.
Here, I provide a quick example using a the same structure as yours (but with specific example).
The abstract class.
public abstract class Pojo implements Serializable {
private static final long serialVersionUID = -4947411931465651278L;
protected int id;
public Pojo() {
// TODO Auto-generated constructor stub
}
public Pojo(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
The first subclass Person
class Person extends Pojo {
private static final long serialVersionUID = -7814628079202659483L;
private String name;
private int age;
public Person(int id, String name, int age) {
super(id);
this.name = name;
this.age = age;
}
#Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", id=" + id + "]";
}
}
The second subclass Address
class Address extends Pojo {
private static final long serialVersionUID = -8266402026827561883L;
private String address;
private String city;
public Address(int id, String address, String city) {
super(id);
this.address = address;
this.city = city;
}
#Override
public String toString() {
return "Address [address=" + address + ", city=" + city + ", id=" + id
+ "]";
}
}
You can then create a collection for this example that will hold both type of instance :
List<Pojo> pojos = new ArrayList<>();
pojos.add(new Address(1, "Address 1", "city1"));
pojos.add(new Address(2, "Address 2", "city2"));
pojos.add(new Person(1, "Name1", 5));
pojos.add(new Person(2, "Name2", 10));
pojos.add(new Person(3, "Name3", 15));
You can use a file for the serialization (because I don't have time to create a socket system ;) ) using :
private static void serialize(String filename, Serializable data)
throws IOException {
try (OutputStream outStream = new FileOutputStream(filename);
ObjectOutputStream fileObjectOut = new ObjectOutputStream(
outStream)) {
fileObjectOut.writeObject(data);
}
}
private static Object deserialize(String filename) throws IOException,
ClassNotFoundException {
try (InputStream inStream = new FileInputStream(filename);
ObjectInputStream fileObjectIn = new ObjectInputStream(inStream)) {
return fileObjectIn.readObject();
}
}
Let serialize and deserialize the list to see if the type are recovered :
serialize("data.ser", pojos);
List<Pojo> tmp = deserialize("data.ser");
System.out.println(tmp);
And you will see the result with the correct type of instance :
[
Address [address=Address 1, city=city1, id=1],
Address [address=Address 2, city=city2, id=2],
Person [name=Name1, age=5, id=1], Person [name=Name2, age=10, id=2],
Person [name=Name3, age=15, id=3]
]
So you could do the same with anything, serialize just a Person, you will need to recover the Object first and use an instanceof to see what is the type recovered.
Pojo p1 = new Person(1, "Name1", 10);
serialize("person.ser", p1);
Object o1 = deserialize("person.ser");
System.out.println(o1);
System.out.println(o1.getClass());
System.out.println(o1 instanceof Person);
Output
Person [name=Name1, age=10, id=1]
class serial.Person
true
I have an arrayList of EmployeeDetails object and another arrayList of EmployeeSalary object.I want to create a new ArrayList that has both the attributes of EmployeeDetails and EmployeeSalary.My EmployeeDetails class has attributes "id" and "name".My EmployeeSalary class has attributes "id" and "salary".I want an arraylist with attributes "id","name" and "salary".
EmployeeDetails Class
public class EmployeeDetails {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
EmployeeSalary class
public class EmployeeSalary {
private String id;
private String sal;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
}
First, set up a map to access the salaries from the IDs:
Map<String, String> salaryMappings = new HashMap();
for(EmployeeSalary salary : salaries) {
salaryMappings.put(salary.getId(), salary.getSal());
}
(where your salary ArrayList is named salaries).
Next, you need a class to store the information (note I'm not writing the accessors for sake of keeping the post short, though you should add them):
class EmployeeInformation {
String id;
String name;
String sal;
public EmployeeInformation(String id, String name, String sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
}
Finally, copy the values into a new ArrayList:
List<EmployeeInformation> infos = new ArrayList<EmployeeInformation>();
for(EmployeeDetails detail : details) {
infos.add(new EmployeeInformation( details.getId(), details.getName(), salaryMappings.get(details.getId()) ));
}
EmployeeSalary should extend Employeedetails
public class EmployeeSalary extends EmployeeDetails{
private String sal;
...
After that, in order to merge two lists arraylist1.addAll(arraylist2) should be invoked.
No need to use HashMap or Map. Just use java 8 lambda :)
Create EmployeeInformation.java class.
public class EmployeeInformation {
String id;
String name;
String sal;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
public EmployeeInformation(String id, String name, String sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
}
Find the full solution.
List<EmployeeDetails> employeeDetailsList = new ArrayList<>();
EmployeeDetails employeeDetails1 = new EmployeeDetails();
employeeDetails1.setId("A");
employeeDetails1.setName("EMP1");
employeeDetailsList.add(employeeDetails1);
EmployeeDetails employeeDetails2 = new EmployeeDetails();
employeeDetails2.setId("B");
employeeDetails2.setName("EMP2");
employeeDetailsList.add(employeeDetails2);
List<EmployeeSalary> employeeSalariesList = new ArrayList<>();
EmployeeSalary employeeSalary1 = new EmployeeSalary();
employeeSalary1.setId("A");
employeeSalary1.setSal("SAL1");
employeeSalariesList.add(employeeSalary1);
EmployeeSalary employeeSalary2 = new EmployeeSalary();
employeeSalary2.setId("B");
employeeSalary2.setSal("SAL2");
employeeSalariesList.add(employeeSalary2);
List<EmployeeInformation> employeeInformationList = new ArrayList<>();
employeeDetailsList.forEach(employeeDetails -> {
String _id = employeeDetails.getId();
String _name = employeeDetails.getName();
employeeSalariesList.stream().filter(employeeSalary -> employeeSalary.getId().equalsIgnoreCase(_id)).forEach(employeeSalary -> {
EmployeeInformation employeeInformation = new EmployeeInformation(_id, _name, employeeSalary.getSal());
employeeInformationList.add(employeeInformation);
});
});
for (EmployeeInformation employeeInformation : employeeInformationList) {
System.out.println(employeeInformation.getId() + "-" + employeeInformation.getName() + "-" + employeeInformation.getSal());
}
Output ->
A-EMP1-SAL1
B-EMP2-SAL2
You can convert the two collections to maps of id->value and then do a secondary lookup.
The following constructs a collection of Map<String, String> with the keys required in your result:
List<EmployeeDetails> details = ...;
List<EmployeeSalary> salaries = ...;
Map<String, EmployeeDetails> detailsMap = details.stream()
.collect(Collectors.groupingBy(EmployeeDetails::getId,
Collectors.reducing(null, (e1, e2) -> e1)));
Map<String, EmployeeSalary> salariesMap = salaries.stream()
.collect(Collectors.groupingBy(EmployeeSalary::getId,
Collectors.reducing(null, (e1, e2) -> e1)));
List<Map<String, String>> summaries = detailsMap.entrySet().stream()
.map(entry -> {
Map<String, String> m = new HashMap<>();
m.put("id", entry.getKey());
m.put("name", entry.getValue().getName());
m.put("salary", salariesMap.get(entry.getKey()).getSal());
return m;
}).collect(Collectors.toList());
It's likely that you'll choose to build a separate class for the summary, having the id, name, and salary fields, instead of using a Map. But this is an idea of how to go about it.
I think, the best solution is to create another class (e.g. EmployeeData) and collect all required data there. In case you do not want (or cannot) modify definitions of EmployeeDetails and EmployeeSalry.
class EmployeeData {
private final String id;
private String name;
private String sal;
public EmployeeData(String id) {
this.id = id;
}
}
private static List<EmployeeData> merge(List<EmployeeDetails> details, List<EmployeeSalary> salaries) {
Map<String, EmployeeData> data = new HashMap<>();
String id;
for (EmployeeDetails detail : details) {
id = detail.getId();
if (!data.containsKey(id))
data.put(id, new EmployeeData(id));
data.get(id).setName(detail.getName());
}
for (EmployeeSalary salary : salaries) {
id = salary.getId();
if (!data.containsKey(id))
data.put(id, new EmployeeData(id));
data.get(id).setSal(salary.getSal());
}
return new ArrayList<>(data.values());
}
I am getting an exception while trying to filter and iterate over a Optional using Java 8. I have an object Subject which is being added in an array list and a value of null also.
Problem Statement: I have an ArrayList, I want to iterate it, filter it and then based on that, only print that record which fulfills the condition.
package com.example.app;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
System.out.println("getSubject: " + getSubjects());
// print the Subject with the name "Math"
System.out.println("getSubject " + getSubjects().filter((Subject s) -> s.getName().equalsIgnoreCase("Math")));
}
private static Optional getSubjects() {
Subject subject1 = new Subject(1, "Math", (short)2, "");
Subject subject2 = new Subject(2, "Social Science", (short)4, "Social Science");
Subject subject3 = new Subject(3, "English", (short)6, "Literature");
List<Subject> subjects = new ArrayList<>();
Optional<List<Subject>> optional = Optional.of(subjects);
subjects.add(subject1);
subjects.add(subject2);
subjects.add(null);
subjects.add(subject3);
return optional;
}
}
class Subject {
int id;
String name;
short type;
String description;
public Subject(int id, String name, short type, String description) {
this.id = id;
this.name = name;
this.type = type;
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public short getType() {
return type;
}
public void setType(short type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "\nSubject{" + "id=" + id + ", name=" + name + ", type=" + type + ", description=" + description + '}'+"\n";
}
}
Using Optional.filter would be used to filter List instances as per your code snippet. This is not what you want:
Optional.of(getSubjects()).filter(predicate) //filters lists, not subjects in lists
Your intention is probably to use the a list of Subject objects, then filter. It's the filter method of the Stream interface that returns an Optional instance:
I'd change this method:
private static List<Subject> getSubjects(){
Subject subject1 = new Subject(1, "Math", (short)2, "");
Subject subject2 = new Subject(2, "Social Science", (short)4, "Social Science");
Subject subject3 = new Subject(3, "English", (short)6, "Literature");
List<Subject> subjects = new ArrayList<>();
subjects.add(subject1);
subjects.add(subject2);
subjects.add(null);
subjects.add(subject3);
return subjects;
}
And then use it as follows:
Optional<Subject> filtered = getSubjects()
.stream().filter(s -> s.getName().equalsIgnoreCase("Math"))
//Find first is just one of the many Stream methods
//returning an optional
//It's correct to use it in this case because you know
//only one value is expected to match the filter predicate.
.findFirst();
In fact, if you expect more than one subject to match your filter, you should collect, instead, instead of picking one. In this case, you don't need an optional:
List<Subject> mathSubjects = getSubjects()
.stream().filter((s -> s.getName().equalsIgnoreCase("Math")))
.collect(Collectors.toList());
You can do it very simply using lambda expression, I am providing you a sample so that you can modify according to your need.
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class Java8Optional {
public static void main(String[] args) {
List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(1, "syed"));
employeeList.add(new Employee(2, "az"));
employeeList.add(null);
employeeList.add(new Employee(4, "Rof"));
employeeList.forEach(n -> Optional.ofNullable(n).ifPresent(e -> System.out.println("Employee ID="+e.employeeId+"\tEmployee Name="+e.employeeName)));
}
static class Employee {
Integer employeeId;
String employeeName;
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employee(Integer employeeId, String employeeName) {
super();
this.employeeId = employeeId;
this.employeeName = employeeName;
}
}
}
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");