I am not too familiar with enum classes in java. And was wondering if this is an appropriate way to do the following.. (or if there is a better way of doing this)
Essentially what I am trying to do is I have a list of Employees and I'd like to associate with it specific subclasses of parent classes.
public enum Employees {
BOB (new Level2Salary(salaryPlan), new SystemsDept())
MARY (new Level3Salary(salaryPlan), new SoftwareDept()),
SUSAN (new Level2Salary(salaryPlan), new SystemsDept()),
PETER (new BaseSalary(salaryPlan), new TestDept());
private Salary salary;
private Dept dept;
Employees(Salary salary, Dept dept){
this.salary = salary;
this.dept = dept;
}
public Salary getSalary() {
return salary;
}
public Salary getDept() {
return dept;
}
}
public class Level2Salary extends Salary {
private SalaryPlan salaryPlan;
public Level2Salary(SalaryPlan salaryPlan) {
this.salaryPLan = salaryPlan;
}
}
public class SystemsDept extends Dept {
public SystemsDept(){}
}
}
I want to be able to do this so when I call Employees.BOB.getSalary() it will return the appropriate instantiated subclass that is associated with this enum value. (i.e. Level2Salary subclass)
If anyone has better suggestions of this besides using enums, feel free to suggest. Thanks
That cannot be done with an enum. However, you can make a non-enum class which acts just like an enum: Create a class which only has private constructors, but which has public static final fields whose types are the class itself. Many classes introduced before Java 5 are examples of this, such as:
TextAttribute
DateFormat.Field
JobState
FileChannel.MapMode
The newer StandardSocketOptions not only follows the above pattern, but also uses generics to do exactly what you want: It allows the NetworkChannel.getOption method to return a different subtype for each constant.
In your case, you would replace your enum type with a class designed like StandardSocketOptions:
public class Employees<S extends Salary, D extends Dept> {
public static final Employees<Level2Salary, SystemsDept> BOB =
new Employees<>(new Level2Salary(salaryPlan), new SystemsDept());
public static final Employees<Level3Salary, SoftwareDept> MARY =
new Employees<>(new Level3Salary(salaryPlan), new SoftwareDept());
public static final Employees<Level2Salary, SystemsDept> SUSAN =
new Employees<>(new Level2Salary(salaryPlan), new SystemsDept());
public static final Employees<BaseSalary, TestDept> PETER =
new Employees<>(new BaseSalary(salaryPlan), new TestDept());
private final S salary;
private final D dept;
private Employees(S salary, D dept){
this.salary = salary;
this.dept = dept;
}
public S getSalary() {
return salary;
}
public D getDept() {
return dept;
}
}
Related
I am new to Java. I am learning about Java Collections and I have question about writing a program to sort by attributes. So I have a class Course with these variables:
public class Course{
private String courseName;
private String courseDescription;
}
And another class Student that contains class Course which is a linked list of Course variables:
public class Student{
private String name;
private LinkedList<Course> courses;
}
public Student(String name) {
this.name = name;
this.courses = new LinkedList<Course>();
}
I want to write a method public void sortCourse() { } in Student class that should accept parameters to specify whether the sorting should be ascending or descending and also based on which course attribute to sort the courses, and print the sorted list of course. How can I write this method?
As Fureeish said in a comment: Make it accept a Comparator.
Like this:
public void sortCourse(Comparator<Course> comparator) {
this.courses.sort(comparator);
}
The caller would then write something like this:
// Sort ascending by name
student.sortCourse(Comparator.comparing(Course::getCourseName));
// Sort decending by name
student.sortCourse(Comparator.comparing(Course::getCourseName).reversed());
// Sort ascending by course level, then description
student.sortCourse(Comparator.comparing(Course::getCourseLevel)
.thenComparing(Course::getCourseDescription));
You can use Comparable interface to sort the courses. For that your Course class need to implements the Comparable interface.
public class Course implements Comparable <Course>{
private String courseName;
private String courseDescription;
public Course(String courseName, String courseDescription){
this.courseName = courseName;
this.courseDescription = courseDescription;
}
public int compareTo(Course c) {
return this.courseName.compareTo(c.courseName);
}
}
Now you can call Collections.sort(student.courses) method to sort the course list.
public class Student{
private String name;
private LinkedList<Course> courses;
public Student(String name) {
this.name = name;
this.courses = new LinkedList<Course>();
}
public void sortCourse(String sortOrder){
if(sortOrder.equals("asc")){
Collections.sort(this.courses);
} else {
Collections.sort(this.courses);
Collections.reverse(this.courses);
}
}
}
I have 2 different classes, Employee, PersonnelManager. I am trying to declare and instantiate an array of Employee in PersonnelManager. without using inheritance, just two completely seperate classes
public abstract class Employee {
private String firstName;
private String lastName;
private double wage;
public Employee() {
firstName = "";
lastName = "";
wage = 0.0;
}
}
public class PersonnelManager {
public Employee [] EmployeesArray;
public PersonnelManager() {
EmployeesArray= {Employee.this()}; // this is not working
}
in the Constructor of PersonnelManager How can I instantiate the array. Thank you.
You can initialize the array like below -
public PersonnelManager() {
EmployeesArray= new EmployeesArray[5];
}
or you can pass the size in constructor to make it dynamic-
public PersonnelManager(int size) {
EmployeesArray= new EmployeesArray[size];
}
Hope this will help you.
public abstract class Employee {
private String firstName;
private String lastName;
private double wage;
public Employee() {
firstName = "";
lastName = "";
wage = 0.0;
}
}
public class PersonnelManager {
public Employee [] EmployeesArray;
public PersonnelManager() {
EmployeesArray= new Employee[10]; // 10 is the size of an array
}
I think you're trying to instantiate an empty array of Employees in your PersonnelManager, but you're using the wrong syntax. You can do that with this:
EmployeesArray = new EmployeesArray[size];
Note that you'll have to supply a size. If you want more flexibility, then you might want to use a List instead of an array:
public class PersonnelManager {
public List<Employee> employees;
public PersonnelManager() {
employees = new ArrayList<>();
}
}
Here is my Code :
public class SearchByLambda {
private Map<String,Consumer<Person>> searchCritertiaHolder = new HashMap<String,Consumer<Person>>();
private static final String AGED = "aged";
public SearchByLambda(){
searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);} );
}
private Consumer<Person> getFilter(String personType){
return searchCritertiaHolder.get(personType);
}
public static void main(String[] args) {
SearchByLambda searchUsage = new SearchByLambda();
Person p = new Person(59,"shailesh");
Person p1 = new Person(58,"ganesh");
searchUsage.getFilter(AGED).accept(p);
searchUsage.getFilter(AGED).accept(p1);
Person.printAgedPersons();
}
}
class Person{
private static List<Person> agedPersons = new ArrayList<>();
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(int age,String name){
this.age = age;
this.name = name;
}
public void filterAgedPerson(Person person){
if(person.getAge() > 58){
agedPersons.add(person);
}
}
public static void printAgedPersons(){
for(Person person : agedPersons){
System.out.println(person.getName());
}
}
}
When I replace following Lambda expression
searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);});
with
searchCritertiaHolder.put(AGED, Person::filterAgedPerson);
it gives me compilation error. I am using java 8 and and compiling through eclipse. Why is this so? Why cannot I assign method reference for instance method of any arbitrary object to consumer functional interface?
Your definition of filterAgedPerson takes a Person as an argument, even though it is not a static method. It doesn't need to, and it shouldn't if you want to use it as a Consumer<Person>. What you are ending up with is something compatible with BiConsumer<Person, Person>.
It might help to think of it this way: method references to non-static methods always take an "extra" argument which is used as this.
The easiest way for you to fix this with your current code structure is to modify the filterAgedPerson method to not take a Person as an argument
public void filterAgedPerson() {
if (this.getAge() > 58) {
agedPersons.add(person);
}
}
As an aside, you might want to also consider making your filters Predicate<Person> instead of Consumer<Person> and moving the results handling elsewhere. This will give you more flexibility as things get more complicated.
I am very new to Java and to programming in general, and I have an assessment to complete where I load employees (with name, age, and department attributes; department can be only one of four enumerated values) into a program that will sort them by age and tell if the age is a prime number. The assignment requires Company, Department, and Employee classes. I am confident that I can figure out age/prime components — I know how to google for algorithms. What I am struggling with is putting all the discrete pieces into a cohesive whole.
Here is what I have so far. I've put in one employee, but the way I'm doing it seems completely inelegant and inefficient. I am sure there is a better way, but I've hit a mental block.
EDIT: as was pointed out below, I was unclear. What I am asking help with is populating the data structure.
Company class:
public class Company {
static Employee one = new Employee();
public static void main(String[] args) {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
}
DepartmentList class:
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public enum DepartmentList {
ACCOUNTING, MARKETING, HUMANRESOURCES, INFORMATIONSYSTEMS;
public static void main(String[] args) {
Map<DepartmentList,String>
enumMap=new EnumMap<DepartmentList,String>(DepartmentList.class);
enumMap.put(DepartmentList.ACCOUNTING, "Accounting");
enumMap.put(DepartmentList.MARKETING, "Marketing");
enumMap.put(DepartmentList.HUMANRESOURCES, "Human Resources");
enumMap.put(DepartmentList.INFORMATIONSYSTEMS, "Information Systems");
Set<DepartmentList> keySet = enumMap.keySet();
for (DepartmentList department : keySet) {
String value = enumMap.get(department);
System.out.println("ENUMMAP VALUE:"+value);
}
}
}
Employee class:
public class Employee {
String empName;
int empAge;
DepartmentList empDept;
Employee() {
}
public String getName() {
return empName;
}
public void setName(String name) {
this.empName = name;
}
public int getAge() {
return empAge;
}
public void setAge(int age) {
this.empAge = age;
}
public DepartmentList getDepartment() {
return empDept;
}
public void setDepartment(DepartmentList department) {
this.empDept = department;
}
public Employee(String empName, int empAge, DepartmentList empDept){
}
}
I also have a Department class, but it's currently empty.
Am I on the right track? Can someone give me a nudge? Thank you!
Don't hard-code the data inside the Java program. Put the data in a file and write methods to load the data.
If you MUST hardcode the data in the program, use something like this sample:
public class Employee
{
String name;
int age;
public Employee(String name, int age)
{
this.name = name;
this.age = age;
}
// getters, setters, etc.
}
In the main program
private static Employee[] empData =
{
new Employee("John Smith", 50),
new Employee("Fred Jones", 25),
.
.
.
};
Now you have a static array of Employee objects that you can "load" into your data structure.
If you're asking if there is something like a property in Java, no, there isn't (at least not yet).
If you're asking how to populate your objects something like an IOC container, like Spring, would be a better choice.
Now as it comes to your code you have two main methods in two different classes. Only one will be called. If you want to create a static instance you will be better do
static Employee one = new Employee("Counting Guru", 55, DepartmentList.ACCOUNTING);
or
static Employee one = new Employee();
static {
one.setName("Counting Guru");
one.setAge(55);
one.setDepartment(DepartmentList.ACCOUNTING);
}
When it comes to the enum then you'll better define a constructor for it
public enum DepartmentList {
ACCOUNTING("Accounting"), MARKETING("Marketing");
private String displayName;
public DepartmentList(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return diplayName;
}
}
In the Employee constructor you need to assign the field values to the ones received as arguments.
I am trying to print the first element on the two arrays in my Athlete class, country and name. I also need to create a object that simulates three dive attemps an athlete had (that is initially set to zero). I am new to OOP and I dont know how to go abouts doing this in my main... as far as constructors go. This is what i have done so far...
this is the main:
import java.util.Random;
import java.util.List;
public class Assignment1 {
public static void main(String[] args) {
Athlete art = new Athlete(name[0], country[0], performance[0]);
}
}
I just really am not sure what to do...
And this is the class with the arrays.
import java.util.Random;
import java.util.List;
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
//Here i would like to create something that would be representing 3 dive attemps (that relate to dive and score. eventually.)
Athlete(String[] name, String[] country, Performance[] performance) {
this.name = name;
this.country=country;
this.performance=performance;
}
public Performance Perform(Dive dive){
dive.getDiveName();
return null;
}
public String[] getName() {
return name;
}
public void setName(String[] name) {
this.name = name;
}
public String[] getCountry() {
return country;
}
public void setCountry(String[] country) {
this.country = country;
}
}
thanks in advance for any help and input!
btw there is other classes too, just not relevant atm..
First, as for your Athlete class, you can remove your Getter and Setter methods since you have declared your instance variables with an access modifier of public. You can access the variables via <ClassName>.<variableName>.
However, if you really want to use that Getter and Setter, change the public modifier to private instead.
Second, for the constructor, you're trying to do a simple technique called shadowing. Shadowing is when you have a method having a parameter with the same name as the declared variable. This is an example of shadowing:
----------Shadowing sample----------
You have the following class:
public String name;
public Person(String name){
this.name = name; // This is Shadowing
}
In your main method for example, you instantiate the Person class as follow:
Person person = new Person("theolc");
Variable name will be equal to "theolc".
----------End of shadowing----------
Let's go back to your question, if you just want to print the first element with your current code, you may remove the Getter and Setter. Remove your parameters on your constructor.
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germany", "USA"};
public Athlete() {
}
In your main method, you could do this.
public static void main(String[] args) {
Athlete art = new Athlete();
System.out.println(art.name[0]);
System.out.println(art.country[0]);
}
}
Currently you can't access the arrays named name and country, because they are member variables of your Athelete class.
Based on what it looks like you're trying to do, this will not work.
These arrays belong in your main class.
Your attempt at an athlete class seems to be dealing with a group of athletes, which is a design fault.
Define a class to represent a single athlete, with fields that represent the athlete's attributes:
public class Athlete {
private final String name;
private final String country;
private List<Performance> performances = new ArrayList<Performance>();
// other fields as required
public Athlete (String name, String country) {
this.name = name;
this.country = country;
}
// getters omitted
public List<Performance> getPerformances() {
return performances;
}
public Performance perform(Dive dive) {
// not sure what your intention is here, but something like this:
Performance p = new Performance(dive, this);
// add new performance to list
performances.add(p);
return p;
}
}
Then your main method would use ti like this:
public class Assignment1 {
public static void main(String[] args) {
String[] name = {"Art", "Dan", "Jen"};
String[] country = {"Canada", "Germant", "USA"};
Dive[] dive = new Dive[]{new Dive("somersault"), new Dive("foo"), new Dive("bar")};
for (int i = 0; i < name.length; i++) {
Athlete athlete = new Athlete(name[i], country[i]);
Performance performance = athlete.perform(dive[i]);
// do something with athlete and/or performance
}
}
}
I think you are a little messed up with what you doing.
Athlete is an object, athlete has a name, i has a city where he lives.
Athlete can dive.
public class Athlete {
private String name;
private String city;
public Athlete (String name, String city){
this.name = name;
this.city = city;
}
--create method dive, (i am not sure what exactly i has to do)
public void dive (){}
}
public class Main{
public static void main (String [] args){
String name = in.next(); //enter name from keyboad
String city = in.next(); //enter city form keybord
--create a new object athlete and pass paramenters name and city into the object
Athlete a = new Athlete (name, city);
}
}
public static void main(String[] args) {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
// initialize your performance array here too.
//Your constructor takes arrays as an argument so you need to be sure to pass in the arrays and not just objects.
Athlete art = new Athlete(name, country, performance);
}
First off, the arrays are pointless, let's get rid of them: all they are doing is providing values for mock data. How you construct mock objects has been debated ad nauseum, but clearly, the code to create the fake Athletes should be inside of a unit test. I would use Joshua Bloch's static builder for the Athlete class, but you only have two attributes right now, so just pass those in a Constructor. Would look like this:
class Athlete {
private String name;
private String country;
private List<Dive> dives;
public Athlete(String name, String country){
this.name = name;
this.country = country;
}
public String getName(){
return this.name;
}
public String getCountry(){
return this.country;
}
public String getDives(){
return this.dives;
}
public void addDive(Dive dive){
this.dives.add(dive);
}
}
Then for the Dive class:
class Dive {
private Athlete athlete;
private Date date;
private double score;
public Dive(Athlete athlete, double score){
this.athlete = athlete;
this.score = score;
this.date = new Date();
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
}
Then make a unit test and just construct the classes, and manipulate them, make sure that they are working. Right now they don't do anything so all you could do is assert that they are retaining the Dives that you are putting in them. Example:
#Test
public void testThatDivesRetainInformation(){
Athlete art = new Athlete("Art", "Canada");
Dive art1 = new Dive(art, 8.5);
Dive art2 = new Dive(art, 8.0);
Dive art3 = new Dive(art, 8.8);
Dive art4 = new Dive(art, 9.2);
assertThat(art.getDives().size(), is(5));
}
Then you could go through and add tests for things like, making sure that you can't construct a dive without an athlete, etc.
You could move construction of the athletes into the setup method of the test so you could use it all over the place. Most IDEs have support for doing that with a refactoring.