Class Level Variable Eligible for GC in Java - java

I have an Employee, an Organization and Test class. The employee contains information related to Employee and Organization class contains Employee list. Please find below source code of both class:
Employee.java
package com.practice;
public class Employee {
private String empId;
private String name;
private int age;
private float salary;
public Employee(final String empId, final String name, final int age, final float salary) {
this.empId = empId;
this.name = name;
this.age = age;
this.salary = salary;
}
public String getEmpId() {
return empId;
}
public void setEmpId(final String empId) {
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(final int age) {
this.age = age;
}
public float getSalary() {
return salary;
}
public void setSalary(final float salary) {
this.salary = salary;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return this.empId + " " + this.name + " " + this.age + " " + this.salary;
}
}
Organization.java
package com.practice;
import java.util.ArrayList;
import java.util.List;
public class Organization {
private final List<Employee> empList = new ArrayList<Employee>();
Organization() {
}
public void addEmployee(final Employee emp) {
this.empList.add(emp);
}
public List<Employee> getEmpList() {
return empList;
}
}
TestGC.java
package com.practice;
public class TestGC {
public static void main(final String[] args) {
final Employee emp = new Employee("E1", "Emp 1", 20, 2000.0f);
final Employee emp2 = new Employee("E1", "Emp 1", 20, 2000.0f);
final Organization org = new Organization();
org.addEmployee(emp);
org.addEmployee(emp2);
System.out.println(org.getEmpList());
}
}
In Organization.java, we have list of Employee object and I have created the object in the same line, that means at class level. So, my question is, will that list be eligible for GC once I'm done with Organization object or it will be a leak in memory? Also, will it make any difference if I instantiate the same object inside constructor?

What you have are regular instance variables (as well as a few local variables). They will be collected normally, when they're no longer reachable. It makes no difference if you instantiate them from the constructors, it'll only add unnecessary code.
It's not that easy to leak memory in Java.

Will that list be eligible for GC once I'm done with Organization
object or it will be a leak in memory?
Yes. List will be eligible for the GC once organization object goes out of scope. All you are using are instance variables, so no need to worry about memory leak unless you have some static variables used in bad way.
will it make any difference if I instantiate the same object inside
constructor?
No.

Related

In Java, how do you create an ArrayList, with one element of that list being another ArrayList, that is unique for each element?

So for example.
I have an ArrayList of people. Created through a people object that contains a name, address, age, etc.
How would I then add another list to that, allowing a unique list of hobbies for each person?
So I could have:
James, 32, England, (Football, Tennis)
Chloe, 21, Wales, (Art)
Tried a few things and struggling with it.
import java.util.ArrayList;
public class People {
int id;
String name;
ArrayList<String> hobbies;
public People(int id, String name, ArrayList<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = hobbies;
}
public People(String name) {
this.name = name;
}
public People() {
// TODO Auto-generated constructor stub
}
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;
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
}
import java.util.ArrayList;
public class Runner {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<People> arrayPeople = new ArrayList<>();
ArrayList<String> hobbies = new ArrayList<>();
hobbies.add("Football");
hobbies.add("Tennis");
arrayPeople.add(new People(1,"Paul", hobbies));
hobbies.add("Golf");
arrayPeople.add(new People(2,"James", hobbies));
System.out.println(arrayPeople);
}
}
This creates a hobby list that is the same for each person, not unique.
This creates a hobby list that is the same for each person, not unique.
That's because member hobbies in [Paul] People object has same value as member hobbies in [James] People object, since they are assigned the same value in method main of class Runner. Hence when you change hobbies variable, in method main of class Runner, you are changing for both Paul and James.
The simplest solution is to change the class constructor so that it creates a copy of the hobbies parameter and assigns the copy to the hobbies member:
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
However, I suggest that you add methods to class People to manipulate hobbies member, including:
addHobby for adding a hobby
removeHobby for removing a hobby
clearHobbies for removing all hobbies
getHobbies that returns a copy of hobbies (so that code that calls the method cannot change hobbies)
Below code demonstrates.
Note that you should always use the interface – in this case java.util.List – rather than the implementation – in this case ArrayList – in the API so that you can change class People without having to change its API. If you change the API of class People then all other classes that use class People – like class Runner in the code in your question – will need to be changed as well.
import java.util.ArrayList;
import java.util.List;
public class People {
private int id;
private String name;
private List<String> hobbies;
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
public People(int id, String name) {
this(id, name, new ArrayList<String>());
}
public People() {
this(0, "");
}
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 void addHobby(String hobby) {
if (!hobbies.contains(hobby)) {
hobbies.add(hobby);
}
}
public void clearHobbies() {
hobbies.clear();
}
public List<String> getHobbies() {
return List.of(hobbies.toArray(new String[]{}));
}
public void removeHobby(String hobby) {
if (hobbies.contains(hobby)) {
hobbies.remove(hobby);
}
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
public static void main(String[] args) {
List<People> arrayPeople = new ArrayList<>();
People paul = new People(1,"Paul");
paul.addHobby("Football");
paul.addHobby("Tennis");
People james = new People(2,"James");
james.addHobby("Football");
james.addHobby("Tennis");
james.addHobby("Golf");
arrayPeople.add(paul);
arrayPeople.add(james);
System.out.println(arrayPeople);
}
}
Running the above code prints the following:
[People [id=1, name=Paul, hobbies=[Football, Tennis]], People [id=2, name=James, hobbies=[Football, Tennis, Golf]]]
The question seemed unclear to me, however I assume that you created lists such as
[name,age,location]
However, this is not an object. If you create a person object, you can add features inside it. So that when you create a person object, then you will have access to add/edit new features. In your case, your features must be:
Name
Age
Location
List (Whatever you name it, type of it must be an arraylist).
To have a list of people:
class Person{
String name;
int age;
String Address;
...
}
and
ArrayList<Person>
For the people class, if you need each hobby in hobbies to be unique you can have a Set class to store hobbies.
class Person{
String name;
int age;
String address;
Set<String> hobbies;
...
}
If the order does not matter you can use HashSet To maintain the order you can use TreeSet or LinkedHashSet.
class person{
String name;
int age;
String address;
TreeSet<String> hobbies;
...
}
class Person{
String name;
int age;
String address;
LinkedHashSet<String> hobbies;
...
}
To add a hobby to a person.
String hobby = "a hobby";
person.add(hobby);
To add hobbies to a person;
String hobby1 = "hobby1";
String hobby1 = "hobby2";
...
Set<String> hobbies = new TreeSet(); // or Set<String> hobbies = new LinkedHashMap();
hobbies.add(hobby1);
hobbies.add(hobby2);
...
person.addAll(hobby);
For another person with the same hobbies, you need to copy the hobbies, then modifying the hobbies of the second person will not affect the hobbies of the first person.
Set<String> new_hobbies = new TreeSet(old_hobbies); // or new LinkedHashSet(old_hobbies);
another_person.addAll(new_hobbies);

How do I resolve wrong output error in java aggregation?

My code is working fine, but in the output, both employees are having same address. Why is it happening so and how can I resolve it?
package practice;
class address{
static String country,state,cityname;
public address(String country, String state, String cityname) {
this.country=country;
this.state=state;
this.cityname=cityname;
}
}
class employee{
String name;
int id;
int age;
address add;
public employee(String name, int id, int age,address add) {
this.name=name;
this.id=id;
this.age=age;
this.add=add;
}
void display() {
System.out.println(name+" "+id+" "+age);
System.out.println("the employee stays at"+ address.country+" "+
address.state+" "+address.cityname);
}
}
public class Document {
public static void main(String[] args) {
// TODO Auto-generated method stub
address a2 = new address("A","B","C");
address a1 = new address("D","E","F");
employee e1 = new employee("lmn",123,20,a2);
employee e2 = new employee("pqr", 456,24,a1);
e1.display();
e2.display();
}
}
The problem is the static variables in address:
class address{
static String country,state,cityname;
...
remove the static keyword.
Also make your properties private and add getter and setter.
Take care of java naming conventions. Class names should start with upper case character

I need to get the max from a Employee class from a Farm class

I need to find and display the the employee who has the maximum salary from the Farm.
this is what I got so far
public class Employee implements Comparable<Employee> {
private String name;
private Integer salary;
public Employee (String name , Integer salary) {
this.name = name;
this.salary = salary;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
public Integer getSalary() {
return salary;
}
public String toString() {
return name + " " + salary;
}
public int compareTo(Employee emp) {
return this.salary.compareTo(emp.getSalary());
}
}
Employee class
public class Farm {
private String name;
private Integer surface;
List<Employee> emp = new ArrayList<Employee>();
public Farm(String name , Integer surface) {
this.name = name;
this.surface = surface;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSurface(Integer surface) {
this.surface = surface;
}
public int getSurface () {
return surface;
}
public String toString() {
return name + " " + surface;
}
public void makeList(String ename , Integer esalary) {
this.emp.add(new Employee(ename,esalary));
}
public void getList() {
for(Employee el : emp)
System.out.println(el);
}
}
And the last one is the main. The thing is that I don't know how can I have more farms and get the max from every single one of them. Can you guys help me?
And this is my mainapp
public class Mainapp {
public static void main(String args[])
{
List <Farm> FarmList = new ArrayList<Farm>();
FarmList.add(new Farm("unirea pizdii", 890030));
FarmList.add(new Farm("pseudo autsm",78594));
FarmList.add(new Farm("haha hihi",854856099));
Farm farm1 = new Farm("Tiguana" , 700);
farm1.makeList("Mihai", 30000);
farm1.makeList("Vladimir", 4000);
farm1.makeList("Tusnic", 3000);
farm1.getList();
Employee emp1 = new Employee(" mihai", 3000);
System.out.println(emp1);
}
}
To get employee with max salary for each farm you can use stream api:
import static java.util.stream.Collectors.*;
Map<Farm, Optional<Employee>> collect =
farmList.stream().collect(groupingBy(Function.identity(),
flatMapping(farm -> farm.getEmployes().stream(),
maxBy(Employee::compareTo))));
Result map has Farm as a key and Employee with max salary as a value
Note: flatMapping method is from java9
There are multiple ways to sort a List in Java, one of them being Collections.sort(List), but in this case it looks like you are trying to retrieve the maximum value from the list, so there's no need to add the extra overhead.
EDIT: JB Nizet suggested using Collections.max(List):
public Employee getMostPaidEmployee() {
return Collections.max(emp);
}
One way to get the most paid employee from the list would be to loop through them and compare each one to the previously "saved" most paid employee:
// Farm.java
public Employee getMostPaidEmployee() {
Employee mostPaid = null;
// Initialize maximum to the lowest possible value.
// If salaries can only be positive you could also initialize this to `0`.
int maximumSalary = Integer.MIN_VALUE;
for (Employee employee : emp) {
if (employee.getSalary() > maximumSalary) {
// Reset the most paid fields
mostPaid = employee;
maximumSalary = employee.getSalary();
}
}
return mostPaid;
}
You can declare this method on the Farm class, so you will be able to call it even if you have multiple instances of Farm:
List<Farm> farms = new ArrayList<>();
// TODO Add farms
// Get the most paid employee in first farm
Employee mostPaid = farms.get(0).getMostPaidEmployee();
In terms of performance, this method is linear, i.e. O(n).

Java ,import not resolved,inheritance,inner class

Begging java programming recently, run into an error. please help
Have two classes , PersonTest.java:
public class PersonTest {
public static void main(String[] args) {
Person person1=new Person("dummy","sdymmt","20","male","washington");
System.out.println("Name: "+person1.getName());
System.out.println("Surname: "+person1.getSurname());
System.out.println("Age: "+person1.getAge());
System.out.println("Gender:" +person1.getGender());
System.out.println("Birthplace: "+person1.getBirthplace());
Person person2= new Person(400);
System.out.println("Income:"+person2.getX()+" mije leke");
System.out.println("Tax:"+person2.Taksat()+" mije leke");
Student student1= new Student("adsd","zedsdsadza");
System.out.println("emri"+student1.getEmer());
}
}
and also Person.java :
public class Person {
private String Name;
private String Surname;
private String Age;
private String Gender;
private String Birthplace;
private double x;
public Person()
{
}
public Person(String Name, String Surname, String Age, String Gender, String Birthplace) {
this.Name = Name;
this.Surname = Surname;
this.Age = Age;
this.Gender = Gender;
this.Birthplace = Birthplace;
}
public String getName() {
return Name;
}
public String getSurname() {
return Surname;
}
public String getAge() {
return Age;
}
public String getGender() {
return Gender;
}
public String getBirthplace() {
return Birthplace;
}
public Person(double x) {
this.x = x;
}
public double getX() {
return x;
}
double Taksat() {
return (0.1 * x);
}
public class Student extends Person {
private String University;
private String Faculty;
public Student(String Universiteti, String Fakulteti) {
super(Name, Surname, Age, Gender, Birthplace);
this.Faculty = Fakulteti;
this.University = Universiteti;
}
public String getFaculty() {
return Faculty;
}
public String getUniversity() {
return University;
}
}
}
Two classes are in the same default package. How to fix the fact that the test class doesn't recognize the inner class student as a class.
Nested non static class are called Inner Classes those classes cannot live without the Outer class (which wrapped them).
Java docs
An instance of InnerClass can exist only within an instance of
OuterClass and has direct access to the methods and fields of its
enclosing instance.
To instantiate an inner class, you must first instantiate the outer
class. Then, create the inner object within the outer object with this
syntax:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Try using:
Person.Student student = person1.new Student(PARAMETERS);
Important Mark:
Of course, you should highly consider that this is not a good design, because you may want this classes to be visible outside of the Person class but also because Person.Student inherits from Person, which it's already contains the Student class, which usually looks like a loop or a circle relationship, which usually not a good idea for the first place.
Because there is no Student class. Since it nested, it's Person.Student

How to modify the already built object in Java, when the Object is built using Builder Pattern?

I have built (Using Builder Pattern) an Employee object with three fields Name, Age and Gender.
public class Employee {
private String name;
private String age;
private String gender;
// Constructor
private Employee(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
}
// Employee Builder
public static class Builder {
private String name;
private String age;
private String gender;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(String age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
}
// Getters
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getGender() {
return gender;
}
}
Now in the Following Class I have built my Employee Object,
public class TestEmployee {
public static void main(String[] args) throws IOException {
Employee employee = new Employee.Builder().age("23").gender("Male").name("John").build();
System.out.println("Name : " + employee.getName());
System.out.println("Age : " + employee.getAge());
System.out.println("Gender : " + employee.getGender());
}
}
How can I modify the Age of the Employee "John" by breaking the already built employee object?
FYI : I don't want to have Setters in my Employee object.
You want to modify an immutable object. Do you see the problem there?
Either add setters (or any methods that mutate the state) or accept that the object is immutable.
You can of course create a new object based on the values of the old one, but it won't be the same object then.
Build another one using Copy-On-Write (reuse existing fields but change age).
Employee.Builder()
.age(employee.getAge() + 1)
.gender(employee.getGender())
.name(employee.getName())
.build();
Keep in mind, it will be another object.
ahh I was also trying to solve my problem with this approach and ironically I stumbled upon this question. I understand the challenge here, we are trying to modify an object with same builder setters but doing so we'll end up with an new object.
I figured out that there is a solution, so after approx 5yrs here's my answer LOL(to someone who's gonna end up here)
first, instead of creating duplicate properties of OuterClass in inner static Builder class. *declare an instance of outer class in Builder class. which means your build() method will return that instance.
this *declaration of instance is intended, as I am planning to create it internally or gonna ask for its memory from outside.
public class Employee {
private String name;
private String age;
private String gender;
public Static Builder builder()
{
return new Builder();
}
public Static Builder modifier(Employee employee)
{
return new Builder(employee);
}
// Employee Builder
public static class Builder {
private Employee employee;
public Builder(Employee employee)
{
this.employee = employee;
}
public Builder()
{
this.employee = new Employee();
}
public Builder name(String name) {
this.employee.name = name;
return this;
}
public Builder age(String age) {
this.employee.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Employee build()
{
return this.employee;
}
}
// Getters
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getGender() {
return gender;
}
}
notice the tweak here, I introduced a modifier that takes Employee object and further allows client to modify it with Builder pattern.
So your client will use it like this...
to create new Employee
Employee employee = Employee.builder().name("abc).age(20).build();
to modify same instance
Employee.modifier(employee)
.name("xyz")
.build();
If you don't want to put setters (and make Employee mutable) you can't modify age of john... instead of this, what you can do is:
employee = new Employee.Builder()
.age("21")
.gender(employee.getGender())
.name(employee.getName())
.build();
If you don't want setters or public non-final fields, then you can add an extra constructor to the builder which will cause an initial state matching the instance, but with the builder setters available. This won't modify the original object, but create a new one based on it.
public static class Builder {
private String name;
private String age;
private String gender;
public Builder(Employee employee) {
this.name = employee.getName();
this.age = employee.getAge();
this.gender = employee.getGender();
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(String age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Employee build() {
return new Employee(this);
}
}
You can then use it as following.
Employee employee = new Employee.Builder().age("23").gender("Male").name("John").build();
Employee employee2 = new Employee.Builder(employee).name("Jane").build();

Categories

Resources