If I had a class with immutable members in Java, I would do this:
class MyClass {
private final String name;
private final int id;
myClass(String name, int id) {
this.name = name;
this.id = id;
}
String getName() { return name; }
int getId() { return id; }
}
In Progress-4GL, you'd typically see something like this: (Please, no lectures on Hungarian Notation. I hate it too, but it's very common in the Progress community, so it's something I just live with.)
CLASS MyClass :
DEFINE VARIABLE mcName as CHARACTER NO-UNDO.
DEFINE VARIABLE miId as INTEGER NO-UNDO.
CONSTRUCTOR PUBLIC MyClass(INPUT ipcName AS CHARACTER,
INPUT ipiId AS INTEGER):
ASSIGN mcName = ipcName
miId = ipiID.
END. /* constructor(char,int)*/
END CLASS. /* MyClass */
I was told in that in Progress 10.2B, they added the ability to make constants/final variables. However, I am unable to find any reference to it anywhere. In my Architect (version 10.2A) I do see that FINAL is considered a keyword. But the documentation behind it simply eludes me.
And if you've ever tried to search for Progress documentation, you know my dilemma.
How can I do immutable variables in Progress 10.2B? Are there any gotchyas I need to be aware of?
Thanks!
EDIT 1 I found documentation on FINAL. It appears to only apply to classes and methods. My current approach is
CLASS ImmutableString :
DEFINE PRIVATE VARIABLE mcValue AS CHARACTER NO-UNDO.
CONSTRUCTOR PUBLIC ImmutableString(INPUT ipcValue AS CHARACTER) :
ASSIGN mcValue = ipcValue.
END.
METHOD PUBLIC CHARACTER getValue() :
RETURN mcValue. /* Is a defensive copy required? */
END METHOD.
END CLASS.
You could also create a public property with a public "GET" and a private "SET":
DEF PUBLIC PROPERTY Value AS CHAR NO-UNDO
GET.
PRIVATE SET.
CONSTRUCTOR PUBLIC ImmutableString(INPUT ipcValue AS CHARACTER) :
Value = ipcValue.
END.
That's a little less code and does the same thing.
EDITED to change the property name to match the original poster's example.
Related
In Objects in Kotlin: Create safe singletons in one line of code (KAD 27) Antonio Leiva states:
In fact, an object is just a data type with a single implementation.
I would expect to see the term instance rather than implementation used here. Is there some nuance that I am missing?
Sure it does have a single instance after all, but I believe what they meant to say is that whatever you write in an object is final and you can not override it. Even if you make it open(for argument purpose), you can not make an anonymous object out of it since the anonymous class can't be used on a SingleTon instance.
So " data type with a single implementation" means, whatever you write is the final implementation. An instance is, after all, a result of some implementation.
For reference, I am adding a decompiled code of object declaration.
public final class Test {
#NotNull
private static final String testMember = "Test";
public static final Test INSTANCE;
#NotNull
public final String getTestMember() {
return testMember;
}
private Test() {
}
static {
Test var0 = new Test();
INSTANCE = var0;
testMember = "Test";
}
}
I'm new to Java, and currently working in Bluej. I have a bit of a problem I can't solve and would appreciate someone helping me out.
Thank you all in advance!
I have these two classes. Song and AudioCD. And I need to write down this method in AudioCD:
" I need to write down a method that will add a new song to the disc if the length of the disc after adding this song is below the maximum length stored in maxLength. '
public class Song{
//Fields
private String name;
private int length; // in minutes
//Constructor
public Song (String name, int length)
{this.name=name;
this.length=length;}
//Return methods
public String GiveName()
{return name;}
public int GiveLength()
{return length;}}
And other one is:
import java.util.ArrayList;
public class AudioCD
{//Fields
private String name;
private String singer;
private int length;
private int maxLength;
private ArrayList<Song> songs;
//Constructor
public AudioCD(String name, String singer, int maxLength)
{this.name=name;
this.length=length;
this.maxLength=maxLength;
length=0;
songs=new ArrayList<Song>();}
}
I tried these two methods:
public void addSong(String Name, int songlength)
{if ((length+songlength)<maxLength) {songs.add(Name);}}
But this just get me a message:
No suitable method found for add(java.lang.String);
Method java.util.Collection.add(Song) is not applicable;
(argument mismatch;java.lang.String cannot be converted to Song);
Other one I tried:
public void addSong(Song Name, int songlength)
{if ((length+songlength)<maxLength) {songs.add(Name);}}
When I compile it, its okay. But I cannot type any parameter for Song when creating a new object.
Please help. :|
I'm not sure exactly what it is you're trying to do, but if you change the ArrayList to type <String> instead of the Song object, you can just append the song's name property (because it is a String) via songs.add(songObject.name)
I'm assuming you just want the ArrayList to contain the names of the songs
Please take a look at the code below:
Public Class A
Public person1 As Person
End Class
Public Class B
Inherits A
Public Function CheckGender() As Boolean
If person1._Gender = "M" Then
CheckGender = True
End If
End Function
End Class
Public Class C
Inherits B
Public Function CheckAge() As Boolean
If person1._Age > 30 Then
CheckAge = True
End If
End Function
End Class
Public Class D
Inherits C
Public Sub SomeMethod()
Dim list As List(Of Person) = New List(Of Person)
Dim p1 As New Person("Ian", "M", 31)
Dim p2 As New Person("Susan", "F", 20)
Dim p3 As New Person("Mark", "M", 22)
list.Add(p1)
list.Add(p2)
list.Add(p3)
For Each Person As Person In list
person1 = Person
If CheckAge() And CheckGender() Then
'Do something
End If
Next
End Sub
Public Shared Sub Main()
Dim d As New D
d.SomeMethod()
End Sub
End Class
Public Class Person
Public _Name As String
Public _Gender As String
Public _Age As String
Public Sub New(ByVal Name As String, ByVal Gender As String, ByVal Age As Integer)
_Name = Name
_Gender = Gender
_Age = Age
End Sub
End Class
c.SomeMethod loops through three persons and does two checks: b.CheckGender and c.CheckAge. CheckGender and CheckAge use an instance variable from the superclass A.
The code in the live environment loops through 100,000 records daily in a database and deletes those where CheckGender and CheckAge are both true. Is it a bad design choice to use instance variables in this scenario? I was always taught to use local variables. I would expect the Person object to be passed to CheckGender and CheckAge on each loop. Or does it really not matter?
Please note that the above code is a hypothetical example. CheckGender and CheckAge are complex functions in the actual application.
As long as CheckGender and CheckAge are not accessing any private, protected or internal member of the classes in hierarchy, and are public functions, and their logic is the same for any instance, being A, B, or C, it is a better design to have these methods in another class. Make them static if possible. You can have them accept the most general implementation of your classes (A for instance) that allows checking either the age or gender. Taken from your code, you can even pass the Person property instead of using any of the A, B and C classes.
Use of inheritance in the above case and such logic is permitted though, as long as you need to do any or all of the following:
Conform to a specific interface or base class, that A, B and C classes have to implement/extend, and that interface or base class provides the CheckGender and CheckAge methods. This can be the only solution if you pass your objects to 3rd party API, that accepts the base class/interface as an argument and internally calls the check methods.
Here is example in C#:
public static class CheckUtil
{
public static bool CheckAgeOfPerson(Person p)
{
return p.Age > 30;
}
public static bool CheckAgeOfObject(A obj)
{
// NOTE: obj.person1 must be accessible - by being either public or internal.
// If this class is in another assembly, internal is not useful
return CheckAgeOfPerson(obj.person1);
}
}
A objA = ...;
B objB = ...;
C objC = ...;
CheckUtil.CheckAgeOfObject(objA);
CheckUtil.CheckAgeOfObject(objB);
CheckUtil.CheckAgeOfObject(objC);
CheckUtil.CheckAgeOfPerson(objA.person1);
CheckUtil.CheckAgeOfPerson(objB.person1);
CheckUtil.CheckAgeOfPerson(objC.person1);
Provide specific implementation to the classes. If you have to some logic in CheckAge for instances of A, but either completely different validation for instances of B, or a combination of the existing and some new logic in C, then inheritance is your friend. Still, if that is the case, I'd prefer exposing the CheckGender and CheckAge to interface and call them via the interface. That way, inheritance is valid, but not mandatory, as long the interface is satisfied.
here is an example in C#:
public interface IGenderCheckable
{
bool CheckGender();
}
public interface IAgeCheckable
{
bool CheckAge();
}
public class A : IAgeCheckable, IGenderCheckable
{
public virtual bool CheckGender()
{
return this.person1.Gender.Equals("M");
}
public virtual bool CheckAge()
{
return this.person1.Age > 30;
}
}
public class B : A
{
public override bool CheckAge()
{
// combine custom logic with new logic
return this.person1.Age < 0 || base.CheckAge();
}
}
For complex scenarios, a combination of both approaches might be also used (of course for far more complex cases than age and gender checks):
public class A : IAgeCheckable, IGenderCheckable
{
...
}
public static class CheckUtil
{
public static bool CheckAge(IAgeCheckable obj)
{
return obj.CheckAge();
}
public static bool CheckGender(IGenderCheckable)
{
return obj.CheckGender();
}
}
About usage of instance variables vs local variables - there is a drawback in performance of using instance variables in .NET especially when they are value types. Use of local member that is int _someIntMember for example gets translated to this._someIntMember - which in turn calls the heap to get the this object, and then accesses its _someIntMember member. Having the member as a local variable, puts its value in the stack, and reads it from there without the unnecessary roundtrip trough the heap. Moreover, the stack is faster than the heap.
However, I cannot say whether too much heap usage is an abuse of it, neither a misuse of local variables when they are used too much. This depends on the performance needed, and the complexity of code. Sometimes local variables make the code more-readable, but if too many, you could easily forget what each one was (and that can be more serious issue than the negligent performance gain). So it is a matter of style and necessity.
In case you're interested in "fixing" your code to make Person a Property rather than a field, change the implementation of Class A as follows:
Public Class A
Public Property Person1 As Person
Public Overridable Function ComputeAge() As Integer
Return Person1.Age
End Function
End Class
The benefit here is you have the ability to add additional abstractions over getting and setting this property down the road if you need to. The compiler will generate a hidden private backing field for the auto property. You would still access the Person1 from any implementing classes:
Public Class B
Inherits A
Public Overrides Function ComputeAge() As Integer
Return MyBase.Person1.Age.AddYears(1)
End Function
End Class
I am trying to write a simple program that has two classes. I want one class (with the main method) to handle all the input and output and the other class to handle all of the mathematics then return the calculations to the main method. I can successfully pass variables from main method to an object in the mathematics class and have tested the results in that method with a println but can't seem to pass the finished calculations back to my main method. Here is my code, please help me understand. Thank you very much
Here is class with main method
import java.util.Scanner;
public class io {
public static void main (String[] args){
Scanner chargeTankStartGaugeFeetInput = new Scanner(System.in);
Scanner chargeTankStartGaugeInchesInput = new Scanner(System.in);
System.out.println("What is the charge tank's start gauge feet: ");
String chargeTankStartGaugeFeet = chargeTankStartGaugeFeetInput.nextLine();
System.out.println("What is the charge tank's start gauge inches: ");
String chargeTankStartGaugeInches = chargeTankStartGaugeInchesInput.nextLine();
math mathObject = new math();
mathObject.changeGaugesToInches(chargeTankStartGaugeFeet,
chargeTankStartGaugeInches);
System.out.println(mathObject.totalInches(totalInches)
+ " is total inches in io");
}
}
I get an error that says "totalInches" in the main method cannot be resolved to a variable. Is my thinking even close as to how this is supposed to work?
And here is the math class
public class math {
public void changeGaugesToInches(String arg1, String arg2) {
double arg1Double = Double.valueOf(arg1).doubleValue();
double arg2Double = Double.valueOf(arg2).doubleValue();
double totalInches = arg1Double * 12 + arg2Double;
System.out.println(totalInches + " is the total inches");
}
}
You can return the value from the method...
public double changeGaugesToInches(...)
{
....
return totalIncehs;
}
Firstly, by convention, all class and enum names in java should begin with a capital letter. Secondly, you may want to use a more descriptive name for your math class, "UnitsConverter" if that is all that it does.
In changeGaugesToInches, you should rename arg1 and arg2 to feet and inches.
Most importantly, you need to change the method to return the result, and assign it to a variable in your main method:
double totalInches = mathObject.changeGaugesToInches(chargeTankStartGaugeFeet, chargeTankStartGaugeInches);
public double changeGaugesToInches(String arg1, String arg2){
//...
return totalInches;
}
Because this method does not use any instance variables, unless you think you might over ride this method in a subclass (to add metric units, for example) the code would be more efficient if you declared it as static. Also, you can probably use integers unless you require more accuracy.
double totalInches = UnitsConverter.changeGaugesToInches(chargeTankStartGaugeFeet, chargeTankStartGaugeInches);
public static int changeGaugesToInches(String feet, String inches){
return changeGaugesToInches( Integer.parseInt(feet), Integer.parseInt(inches) );
}
// this method can be used more efficiently from parts of your app that already have the units as integers.
public static int changeGaugesToInches(int feet, int in
//...
return totalInches;
}
Any void method can't have return value. Since,
public void changeGaugesToInches(String arg1, String arg2) is a void method therefore it has no return type.
If you make it static then you can't use math mathObject = new math();
One method of my class need fresh copy of some array for internal stuff, so I should write something like that:
public void FrequentlyCalledMethod {
int[] a = new int[100];
....
But because method is frequently called and because content of the array doesn't make sense (it will be replaced anyway) and because array is big enough i want to optimize and write something like that:
private int[] a = new int[100];
public void FrequentlyCalledMethod {
....
Assuming that method is called 100 times per second I will save about 100 * 100 * sizeof(int) bytes of heap memory every second.
The problem is that now class declaration is "dirty". It contains in field the information that only one method needs. Having too much such fields will make class very "unreadable" as "normal" fields will be mixed with "perfomance optimizations" field.
What can I do? Or I should just choose either perfomance or readablity? Can I have both somehow?
No your class declaration is not dirty. Class declaration is dirty only when you mangle its public interface. And this is a private field. Private fields are used for this.
If you are too worried about the too many private variables then try using small classes. If a method needs 3 private variables you can create a class with those 3 variables and store the object as private filed in current class.
class A{
private int a;
private int b;
private int c;
public int get_num(){
return a+b+c;
}
}
you can use this,
class B{
private int a;
private int b;
private int c;
public int get_num(){
return a+b+c;
}
}
class A{
private B b;
public int get_num(){
return b.get_num();
}
}
If the first case, the array inside FrequentlyCalledMethod is referenced using a local variable, so it will be garbage-collected when the method ends: there's no heap over-usage in that scenario.
However, if you declare your array as a member attribute; the array instance will persist for all your parent-object life, even if the method FrequentlyCalledMethod is called or not.
In conclusion, if you wanna preserve heap-space and make your program more memory efficient go with local attributes and avoid instance variables in your particular case.