I would like to know your opinions on which you find is a better approach to have a list filled up by a different method. I know there isn't a definite answer, but I would like to see reasonable pros and cons.
Approach 1.
private List<Snap> snapList;
snapList = getSnapList();
Approach 2.
private List<Snap> snapList = new ArrayList<Snap>();
fillSnapList(snapList);
Thanks,
Matyas
Why not follow the Java API's Collections class and make your fill methods static (if it makes sense and is independent of object state).
Collections.fill( mylist, 0 );
like
MyListFiller.fill( myList, args );
At any rate, creating a filler interface makes sense if the fill method plans to change. If you're not really "filling", but returning object state of some kind, just have the given method build the List and return it.
public List<Object> getMyStuff()
{
//build and return my stuff
}
It depends on the situation.
A method like getSnapList() is appropriate in situations like the following:
The method you're writing doesn't want to care about where the list came from.
The method shouldn't know what kind of list it's getting - for example, if you want to change to using a LinkedList, then you can do it in getSnapList() instead of all the methods that call fillSnapList().
You will only ever want to fill new lists.
A method like fillSnapList() is appropriate in situations like the following:
You may want to fill the list more than one time.
You may want to vary the way the list is filled (i.e. what gets put into it).
You need to fill a list that someone else hands you.
You need to share the list among more than one class or object, and you might need to refill it at some point in its lifespan.
I like approach 1 better than approach 2, because the list is really the output of the method that you're calling. Approach 1 makes that more clear than approach 2.
Also, approach 1 gives the method the opportunity to return an unmodifyable list. You might want this if the list should be filled once and shouldn't be modified later.
Java is not a functional programming language, but the first approach is more in the functional programming style than the second approach (in functional programming, immutability and avoiding mutable state are important ideas - and one important advantage of those is that they make concurrent programming easier, which is also useful in a non-functional programming language).
One con for the first option is that the method name you have choosen (getSnapList()) is often considered a simple accessor, ie return the reference for the field snapList. In your design, it is implied that you will be creating the list if it doesnt exist and filling it with data, which would be introducing a side effect to the normal idiom.
Due to this and as it is better to be explicit, I prefer the second option.
I prefer approach #1 because the method can be overridden by a sub class that would want to use a different List implementation. Also, I think that naming a factory method as a getter is confusing, I would rather name it newSnapList() or createSnapList().
Related
I have an ArrayList where I want to call two methods on the first two objects in the list, and different methods on the rest, how can I do this the easiest way?
So far I have this
ArrayList<Material> materials = new ArrayList();
StyklisteMetodeKlasse.fillArray(materials);
for(Material materialer: materials.subList(0, 1)){
int brugerInput = 0; // this is only a temporary varible
materialer.setAmount(Material.calculatePlanks(brugerInput, materialer.getLength()));
materialer.setAmount(Material.calculatePlanks(brugerInput, materialer.getLength()));
//here is some code where i call different methods on the rest of the materials
When I call a method on the "materialer" does it apply for all the objects or just the first, then the second?
The best approach would most likely be the simplest one. Using polymorphism, and try and get the type of the object at runtime and select what you need to do, would be a sleek solution, but as you said, it might get complicated, especially if you do not have control over the structure and nature of the objects being passed to you.
Alternatively, you could make your classes implement an interface which abstracts the operation that you would need to do. This would allow you to always call the same method, without having to worry about who is what.
As it has been pointed out in the comments, having hardcoded index values could potentially cause more trouble than it will ever solve, since it assumes that who ever is consuming your method has inside knowledge of it how specifically works, as opposed to what it should do.
Most likely, the best approach would be to change your method to take 2 lists, as opposed to 1. This approach is easier to understand and also gives you more control and has you make less assumptions, which is usually always a good thing.
I'll make it short:
public aClass[] changeClassSlightly(aClass[] ac) {
// changing various things in the class
// changes done
return ac;
}
meanwhile, in the main:
aClass test = new aClass();
test = changeClassSlightly(test);
So,
is this an inefficient / looked-down-uppon or unstandard way of doing things, when wanting to implement a functionality regarding a certain class into a different class?
In my case, the here called "aClass" is a fairly simple one, but when these things get bigger and bigger, taking the whole object and spitting it out slightly changed may be considered bad programming.
Is it, though? Is it the sighn of bad data structure or common practise in Java development?
Thanks a lot in advance and thanks for bearing with me :)
I see two different questions here. Inside of changeClassSlightly(...), it looks like you're talking about mutating the ac argument. The code in your question also seems to be asking about local variable reuse, since test is both the argument and the variable containing the value returned by changeClassSlightly(...).
In general, I personally prefer using immutable objects and data structures. I also try to avoid mutating arguments. See Effective Java, Item 15: Minimize Mutability.
If a function is pure it's generally easier to reason about.
But this is very much a matter of opinion.
As for reusing the local variable: I try to avoid doing that, too, but it's really not a big deal either way.
From a performance perspective your code is not ideal. If you can set values in the constructor you can use final fields (immutable, so always thread-safe and easy for the JVM to optimize). Furthermore the values set in the constructor can be safely read without synchronization. If you use a setter later on you need to synchronize or risk not getting the new value in other threads. Synchronization is not as expensive as it once was, but it should be avoided where possible.
I would recommend the builder pattern instead.
I'm currently moving from C++ to Java for work and am having difficulty without const and pointers to make sure intent is always clear. One of the largest problems I'm having is with returning a modified object of the same type.
Take for example a filter function. It's used to filter out values.
public List<int> filter(List<Integer> values) {
...
}
Here everything is Serializable so we could copy the whole list first then modify the contents and return it. Seems a little pointlessly inefficient though. Especially if that list is large. Also copying your inputs every time looks quite clumsy.
We could pass it in normally, modify it and make it clear that we are doing that from the name:
public void modifyInputListWithFilter(List<Integer> values) {
...
}
This is the cleanest approach I can think of - you can copy it before hand if you need to, otherwise just pass it in. However I would still rather not modify input parameters.
We could make the List a member variable of the class we are in and add the filter method to the current class. Chances are though that now our class is doing more than one thing.
We could consider moving the List to it's own class which filter is a function of. It seems a little excessive for one variable though, we'll quickly have more classes than we can keep a track of. Also if we only use this strategy and more than just filtering happens to the List class will unavoidably start doing more than one thing.
So what is the best way of writing this and why?
The short answer is that there is not a single best way. Different scenarios will call for different approaches. Different design patterns will call for different approaches.
You've suggested two approaches, and either one of them might be valid depending on the scenario.
I will say that there is nothing inherently wrong with modifying a List that you pass into a function: take a look at the Collections.sort() function, for example. There is also nothing wrong with returning a copy of the List instead.
The only "rule" here is a Liskov rule (not the Liskov rule): your function should do whatever its documentation says it will do. If you're going to modify the List, make sure your documentation says so. If you aren't, make sure it says that instead.
I've been looking at a lot of code recently (for my own benefit, as I'm still learning to program), and I've noticed a number of Java projects (from what appear to be well respected programmers) wherein they use some sort of immediate down-casting.
I actually have multiple examples, but here's one that I pulled straight from the code:
public Set<Coordinates> neighboringCoordinates() {
HashSet<Coordinates> neighbors = new HashSet<Coordinates>();
neighbors.add(getNorthWest());
neighbors.add(getNorth());
neighbors.add(getNorthEast());
neighbors.add(getWest());
neighbors.add(getEast());
neighbors.add(getSouthEast());
neighbors.add(getSouth());
neighbors.add(getSouthWest());
return neighbors;
}
And from the same project, here's another (perhaps more concise) example:
private Set<Coordinates> liveCellCoordinates = new HashSet<Coordinates>();
In the first example, you can see that the method has a return type of Set<Coordinates> - however, that specific method will always only return a HashSet - and no other type of Set.
In the second example, liveCellCoordinates is initially defined as a Set<Coordinates>, but is immediately turned into a HashSet.
And it's not just this single, specific project - I've found this to be the case in multiple projects.
I am curious as to what the logic is behind this? Is there some code-conventions that would consider this good practice? Does it make the program faster or more efficient somehow? What benefit would it have?
When you are designing a method signature, it is usually better to only pin down what needs to be pinned down. In the first example, by specifying only that the method returns a Set (instead of a HashSet specifically), the implementer is free to change the implementation if it turns out that a HashSet is not the right data structure. If the method had been declared to return a HashSet, then all code that depended on the object being specifically a HashSet instead of the more general Set type would also need to be revised.
A realistic example would be if it was decided that neighboringCoordinates() needed to return a thread-safe Set object. As written, this would be very simple to do—replace the last line of the method with:
return Collections.synchronizedSet(neighbors);
As it turns out, the Set object returned by synchronizedSet() is not assignment-compatible with HashSet. Good thing the method was declared to return a Set!
A similar consideration applies to the second case. Code in the class that uses liveCellCoordinates shouldn't need to know anything more than that it is a Set. (In fact, in the first example, I would have expected to see:
Set<Coordinates> neighbors = new HashSet<Coordinates>();
at the top of the method.)
Because now if they change the type in the future, any code depending on neighboringCoordinates does not have to be updated.
Let's you had:
HashedSet<Coordinates> c = neighboringCoordinates()
Now, let's say they change their code to use a different implementation of set. Guess what, you have to change your code too.
But, if you have:
Set<Coordinates> c = neighboringCoordinates()
As long as their collection still implements set, they can change whatever they want internally without affecting your code.
Basically, it's just being the least specific possible (within reason) for the sake of hiding internal details. Your code only cares that it can access the collection as a set. It doesn't care what specific type of set it is, if that makes sense. Thus, why make your code be coupled to a HashedSet?
In the first example, that the method will always only return a HashSet is an implementation detail that users of the class should not have to know. This frees the developer to use a different implementation if it is desirable.
The design principle in play here is "always prefer specifying abstract types".
Set is abstract; there is no such concrete class Set - it's an interface, which is by definition abstract. The method's contract is to return a Set - it's up the developer to chose what kind of Set to return.
You should do this with fields as well, eg:
private List<String> names = new ArrayList<String>;
not
private ArrayList<String> names = new ArrayList<String>;
Later, you may want to change to using a LinkedList - specifying the abstract type allows you to do this with no code changes (except for the initializtion of course).
The question is how you want to use the variable. e.g. is it in your context important that it is a HashSet? If not, you should say what you need, and this is just a Set.
Things were different if you would use e.g. TreeSet here. Then you would lose the information that the Set is sorted, and if your algorithm relies on this property, changing the implementation to HashSet would be a disaster. In this case the best solution would be to write SortedSet<Coordinates> set = new TreeSet<Coordinates>();. Or imagine you would write List<String> list = new LinkedList<String>();: That's ok if you want to use list just as list, but you wouldn't be able to use the LinkedList as deque any longer, as methods like offerFirst or peekLast are not on the List interface.
So the general rule is: Be as general as possible, but as specific as needed. Ask yourself what you really need. Does a certain interface provide all functionality and promises you need? If yes, then use it. Else be more specific, use another interface or the class itself as type.
Here is another reason. It's because more general (abstract) types have fewer behaviors which is good because there is less room to mess up.
For example, let's say you implemented a method like this: List<User> users = getUsers(); when in fact you could have used a more abstract type like this: Collection<User> users = getUsers();. Now Bob might assume wrongly that your method returns users in alphabetic order and create a bug. Had you used Collection, there wouldn't have been such confusion.
It's quite simple.
In your example, the method returns Set. From an API designer's point of view this has one significant advantage, compared to returning HashSet.
If at some point, the programmer decides to use SuperPerformantSetForDirections then he can do it without changing the public API, if the new class extends Set.
The trick is "code to the interface".
The reason for this is that in 99.9% of the cases you just want the behavior from HashSet/TreeSet/WhateverSet that conforms to the Set-interface implemented by all of them. It keeps your code simpler, and the only reason you actually need to say HashSet is to specify what behavior the Set you need has.
As you may know HashSet is relatively fast but returns items in seemingly random order. TreeSet is a bit slower, but returns items in alphabetical order. Your code does not care, as long as it behaves like a Set.
This gives simpler code, easier to work with.
Note that the typical choices for a Set is a HashSet, Map is HashMap and List is ArrayList. If you use a non-typical (for you) implementation, there should be a good reason for it (like, needing the alphabetical sorting) and that reason should be put in a comment next to the new statement. Makes the life easier for future maintainers.
This question already has answers here:
What does it mean to "program to an interface"?
(33 answers)
Closed 6 years ago.
This is a real beginner question (I'm still learning the Java basics).
I can (sort of) understand why methods would return a List<String> rather than an ArrayList<String>, or why they would accept a List parameter rather than an ArrayList. If it makes no difference to the method (i.e., if no special methods from ArrayList are required), this would make the method more flexible, and easier to use for callers. The same thing goes for other collection types, like Set or Map.
What I don't understand: it appears to be common practice to create local variables like this:
List<String> list = new ArrayList<String>();
While this form is less frequent:
ArrayList<String> list = new ArrayList<String>();
What's the advantage here?
All I can see is a minor disadvantage: a separate "import" line for java.util.List has to be added. Technically, "import java.util.*" could be used, but I don't see that very often either, probably because the "import" lines are added automatically by some IDE.
When you read
List<String> list = new ArrayList<String>();
you get the idea that all you care about is being a List<String> and you put less emphasis on the actual implementation. Also, you restrict yourself to members declared by List<String> and not the particular implementation. You don't care if your data is stored in a linear array or some fancy data structure, as long as it looks like a List<String>.
On the other hand, reading the second line gives you the idea that the code cares about the variable being ArrayList<String>. By writing this, you are implicitly saying (to future readers) that you shouldn't blindly change actual object type because the rest of the code relies on the fact that it is really an ArrayList<String>.
Using the interface allows you to quickly change the underlying implementation of the List/Map/Set/etc.
It's not about saving keystrokes, it's about changing implementation quickly. Ideally, you shouldn't be exposing the underlying specific methods of the implementation and just use the interface required.
I would suggest thinking about this from the other end around. Usually you want a List or a Set or any other Collection type - and you really do not care in your code how exactly this is implemented. Hence your code just works with a List and do whatever it needs to do (also phrased as "always code to interfaces").
When you create the List, you need to decide what actual implementation you want. For most purposes ArrayList is "good enough", but your code really doesn't care. By sticking to using the interface you convey this to the future reader.
For instance I have a habit of having debug code in my main method which dumps the system properties to System.out - it is usually much nicer to have them sorted. The easiest way is to simply let "Map map = new TreeMap(properties);" and THEN iterate through them, as TreeMap returns the keys sorted.
When you learn more about Java, you will also see that interfaces are very helpful in testing and mocking, since you can create objects with behaviour specified at runtime conforming to a given interface. An advanced (but simple) example can be seen at http://www.exampledepot.com/egs/java.lang.reflect/ProxyClass.html
if later you want to change implementation of the list and use for example LinkedList(maybe for better performance) you dont have to change the whole code(and API if its library). if order doesnt matter you should return Collection so later on you can easily change it to Set if you would need items to be sorted.
The best explanation I can come up with (because I don't program in Java as frequently as in other languages) is that it make it easier to change the "back-end" list type while maintaining the same code/interface everything else is relying on. If you declare it as a more specific type first, then later decide you want a different kind... if something happens to use an ArrayList-specific method, that's extra work.
Of course, if you actually need ArrayList-specific behavior, you'd go with the specific variable type instead.
The point is to identify the behavior you want/need and then use the interface that provides that behavior. The is the type for your variable. Then, use the implementation that meets your other needs - efficiency, etc. This is what you create with "new". This duality is one of the major ideas behind OOD. The issue is not particularly significant when you are dealing with local variables, but it rarely hurts to follow good coding practices all the time.
Basically this comes from people who have to run large projects, possibly other reasons - you hear it all the time. Why, I don't actually know. If you have need of an array list, or Hash Map or Hash Set or whatever else I see no point in eliminating methods by casting to an interface.
Let us say for example, recently I learned how to use and implemented HashSet as a principle data structure. Suppose, for whatever reason, I went to work on a team. Would not that person need to know that the data was keyed on hashing approaches rather than being ordered by some basis? The back-end approach noted by Twisol works in C/C++ where you can expose the headers and sell a library thus, if someone knows how to do that in Java I would imagine they would use JNI - at which point is seems simpler to me to use C/C++ where you can expose the headers and build libs using established tools for that purpose.
By the time you can get someone who can install a jar file in the extensions dir it would seem to me that entity could be jus short steps away - I dropped several crypto libs in the extensions directory, that was handy, but I would really like to see a clear, concise basis elucidated. I imagine they do that all the time.
At this point it sounds to me like classic obfuscation, but beware: You have some coding to do before the issue is of consequence.