To answer the precise question "Why doesn't Set provide an operation to get an element that equals another element?", the answer would be: because the designers of the collection framework were not very forward looking. They didn't anticipate your very legitimate use case, naively tried to "model the mathematical set abstraction" (from the javadoc) and simply forgot to add the useful get() method.
Now to the implied question "how do you get the element then": I think the best solution is to use a Map<E,E> instead of a Set<E>, to map the elements to themselves. In that way, you can efficiently retrieve an element from the "set", because the get() method of the Map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of Set that offers the additional get() method, encapsulating the Map.
The following answers are in my opinion bad or wrong:
"You don't need to get the element, because you already have an equal object": the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the Set, not the state of the object used as a "query".
"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.
To answer the precise question "Why doesn't Set provide an operation to get an element that equals another element?", the answer would be: because the designers of the collection framework were not very forward looking. They didn't anticipate your very legitimate use case, naively tried to "model the mathematical set abstraction" (from the javadoc) and simply forgot to add the useful get() method.
Now to the implied question "how do you get the element then": I think the best solution is to use a Map<E,E> instead of a Set<E>, to map the elements to themselves. In that way, you can efficiently retrieve an element from the "set", because the get() method of the Map will find the element using an efficient hash table or tree algorithm. If you wanted, you could write your own implementation of Set that offers the additional get() method, encapsulating the Map.
The following answers are in my opinion bad or wrong:
"You don't need to get the element, because you already have an equal object": the assertion is wrong, as you already showed in the question. Two objects that are equal still can have different state that is not relevant to the object equality. The goal is to get access to this state of the element contained in the Set, not the state of the object used as a "query".
"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.
There would be no point of getting the element if it is equal. A Map is better suited for this usecase.
If you still want to find the element you have no other option but to use the iterator:
public static void main(String[] args) {
Set<Foo> set = new HashSet<Foo>();
set.add(new Foo("Hello"));
for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
Foo f = it.next();
if (f.equals(new Foo("Hello")))
System.out.println("foo found");
}
}
static class Foo {
String string;
Foo(String string) {
this.string = string;
}
@Override
public int hashCode() {
return string.hashCode();
}
@Override
public boolean equals(Object obj) {
return string.equals(((Foo) obj).string);
}
}
class - What is the use of get and set in java.And where should it be used? - Stack Overflow
Set and Get Methods in java? - Stack Overflow
java - Should "Set" have a Get method? - Software Engineering Stack Exchange
Need help understanding "get" and "set" methods in Java.
Set and Get methods are a pattern of data encapsulation. Instead of accessing class member variables directly, you define get methods to access these variables, and set methods to modify them. By encapsulating them in this manner, you have control over the public interface, should you need to change the inner workings of the class in the future.
For example, for a member variable:
Integer x;
You might have methods:
Integer getX(){ return x; }
void setX(Integer x){ this.x = x; }
chiccodoro also mentioned an important point. If you only want to allow read access to the field for any foreign classes, you can do that by only providing a public get method and keeping the set private or not providing a set at all.
I want to add to other answers that setters can be used to prevent putting the object in an invalid state.
For instance let's suppose that I've to set a TaxId, modelled as a String. The first version of the setter can be as follows:
private String taxId;
public void setTaxId(String taxId) {
this.taxId = taxId;
}
However we'd better prevent the use to set the object with an invalid taxId, so we can introduce a check:
private String taxId;
public void setTaxId(String taxId) throws IllegalArgumentException {
if (isTaxIdValid(taxId)) {
throw new IllegalArgumentException("Tax Id '" + taxId + "' is invalid");
}
this.taxId = taxId;
}
The next step, to improve the modularity of the program, is to make the TaxId itself as an Object, able to check itself.
private final TaxId taxId = new TaxId()
public void setTaxId(String taxIdString) throws IllegalArgumentException {
taxId.set(taxIdString); //will throw exception if not valid
}
Similarly for the getter, what if we don't have a value yet? Maybe we want to have a different path, we could say:
public String getTaxId() throws IllegalStateException {
return taxId.get(); //will throw exception if not set
}
The problem here isn't that HashSet lacks a Get method, it's that your code makes no sense from the perspective of the HashSet type.
That Get method is effectively, "get me this value , please", to which the .NET framework folk would sensibly reply, "eh? You already have that value <confused face />".
If you want to store items and then retrieve them based on matching another slightly different value, then use Dictionary<String, MyClass> as you can then do:
var mset = new Dictionary<String, MyClass>();
mset.Add("Hello", new MyClass {A = "Hello", B = "Bye"});
var item = mset["Hello"];
Console.WriteLine(item.B); // will print Bye
The information of equality leaks from the encapsulated class. If I wanted to change the set of properties involved in
Equals, I would have to change the code outsideMyClass...
Well yes, but that's because MyClass runs amok with the principle of least astonishment (POLA). With that equality functionality encapsulated, it is completely reasonable to assume that the following code is valid:
HashSet<MyClass> mset = new HashSet<MyClass>();
mset.Add(new MyClass {A = "Hello", B = "Bye"});
if (mset.Contains(new MyClass {A = "Hello", B = "See you"}))
{
// this code is unreachable.
}
To prevent this, MyClass needs to be clearly documented as to its odd form of equality. Having done that, it's no longer encapsulated and changing how that equality works would break the open/closed principle. Ergo, it shouldn't change and therefore Dictionary<String, MyClass> is a good solution for this odd requirement.
You already have the item that is "in" the set - you passed it as the key.
"But it isn't the instance that I called Add with" - Yes, but you specifically claimed that they were equal.
A Set is also a special case of a Map|Dictionary, with void as the value type (well the useless methods are not defined, but that doesn't matter).
The data structure you are looking for is a Dictionary<X, MyClass> where X somehow gets the As out of the MyClasses.
The C# Dictionary type is nice in this regard, as it allows you to supply an IEqualityComparer for the keys.
For the example given, I would have the following:
public class MyClass {
public string A {get; set;}
public string B {get; set;}
}
public class MyClassEquivalentAs : IEqualityComparer<MyClass>{
public override bool Equals(MyClass left, MyClass right) {
if (Object.ReferenceEquals(left, null) && Object.ReferenceEquals(right, null))
{
return true;
}
else if (Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null))
{
return false;
}
return left.A == right.A;
}
public override int GetHashCode(MyClass obj) {
return obj?.A != null ? obj.A.GetHashCode() : 0;
}
}
Used thusly:
var mset = new Dictionary<MyClass, MyClass>(new MyClassEquivalentAs());
var bye = new MyClass {A = "Hello", B = "Bye"};
var seeyou = new MyClass {A = "Hello", B = "See you"};
mset.Add(bye);
if (mset.Contains(seeyou)) {
//something
}
MyClass item = mset[seeyou];
Console.WriteLine(item.B); // prints Bye
I am really struggling with understanding how get and set methods work. Could someone explain it to me or direct me somewhere that has good, solid, and unfortunately simple explanations on how they work. Thanks in advance!
Using Getters / Setters vs using Fields
As a rule of thumb:
use the variables directly from the same class (actually from the same .java file, so inner classes are ok too), use Getters / Setters from other classes.
The simple rule is: never use direct access (except, of course, when referring to them from inside the class).
- field access can't be proxied
- you may want to have some event notification
- you may want to guard against race conditions
- expression languages support setters and getters
- theoretically this breaks encapsulation. (If we are pedantic, setter and getter for all fields also breaks encapsulation though)
- you may want to perform some extra logic inside the setter or getter, but that is rarely advisable, since consumers expect this to follow the convention - i.e. being a simple getter/setter.
- you can specify only a setter or only a getter, thus achieving read-only, or write-only access.
Even if this does not happen that you need any of these, it is not unlikely. And if you start with field access, it will be harder to change.
I’m new to programming and feel so confused about this.
I've noticed, while looking over other people's code, that they use a "get" and "set" method to access a static member of a class (typically int, float, doubles, and strings). I'm wondering why? Wouldnt it be just as effective to access it by simply referencing that specific variable?
An example:
public class A {
public static int p = 0;
public static int getVarP() {
return p;
}
public static void setVarP(int i) {
p = i;
}
class B {
public static int n = A.getVarP;
public B() {
A.setVarP(n);
}
}So why not just say
public static int n = A.p;
Is this just something that people do just because others do it? Or is there a specific reason?