I have run into such cases on 3 different occasions now. Most of the times when refactoring some code.
Lets say I have:
//code block A
List<Bar> foo = doSomething(inputParams);
//code block B
Now, I need to refactor the code such that I want to use doSomething() method's process to do something else too. Lets say,create a map too (Bar.id -> Bar.name).
Is there an elegant way to do this without passing a mutable map to doSomething() and not duplicating the code to another doSomethingDifferent()?
Dummy implementation:
doSomething(){
List<Bar> ret = new ArrayList<Bar>();
while(//condition){
ret.add(new Bar());
}
returrn ret;
}
doSomethingDifferently(){
Map<Integer, String> ret = new HashMap<Integer, String>();
while(//condition){
Bar b = new Bar()
ret.put(b.getId(),b.getName());
}
returrn ret;
}
Summary:
Is there a better way than the possible solutions below?
Solution 1:(repeated code)
List<Bar> foo = doSomething(inputParams);
Map<Integer,String> foobar = doSomethingDifferent(inputParams); //Very similar to doSomething
Solution 2:(hard to read)
Map<Integer,String> foobar = new HashMap<Integer,String>();
List<Bar> foo = doSomething(inputParams, foobar); //mutate the map
You're returning different data structures..
List<Bar> foo = doSomething(inputParams);
Map<Integer,String> foobar = doSomethingDifferent(inputParams);
Are you sure they do similar things? If so, you could extract common part or change them to return same type and after that it will be easily seen what you can do not to duplicate code.
What your example methods do is different enough to have different method names. E.g. createListFrom(param), createMapFrom(param). Combining that with the same name is just confusing. And I would not count calling doSomething in place and doSomethingElse in another place repetition. The broader concept is maybe repeating.
One way to approach this is to move duplicate code into another method. Same / similar code is
while(condition) {}
Bar b = new Bar()
add b somehow to some sort of collection.
The generic version of your methods could look like
private void doSomethingGeneric(? param, GenericWayToHandle handler) {
while (condition) {
Bar b = createBar();
handler.doSomethingWith(b);
}
}
"Short" example how you could implement that
public List<Object> doSomethingList(int param) {
ListHandler handler = new ListHandler();
doSomethingGeneric(param, handler);
return handler.list;
}
public Map<Object, Object> doSomethingMap(int param) {
MapHandler handler = new MapHandler();
doSomethingGeneric(param, handler);
return handler.map;
}
private void doSomethingGeneric(int param, CollectionHandler handler) {
for (int i = 0; i < param; i++) {
handler.handle("Hello");
}
}
private interface CollectionHandler {
void handle(String string);
}
private static class MapHandler implements CollectionHandler {
public final Map<Object, Object> map = new HashMap<Object, Object>();
#Override
public void handle(String string) {
map.put(string, string);
}
}
private static class ListHandler implements CollectionHandler {
public final List<Object> list = new ArrayList<Object>();
#Override
public void handle(String string) {
list.add(string);
}
}
It's unfortunately pretty ugly to handle for each situations like that and Java 8 will simplify that via closures.
The other way to approach your problem is to use the output of one method to derive another version from it.
e.g. (very similar to what you posted)
List<Bar> bars = createBarList(inputParams); // doSomething
Map<Integer,String> foobar = deriveMap(bars); // doSomethingSimilar
where deriveMap would just iterate over the list and create a map. That's the place where this code would be now
for(Bar b: input)
ret.put(b.getId(),b.getName());
It's ultimately up to you what those methods do and how they should be used. The name of a method can help a lot to express the intention & help to use them correctly. Don't give that up by merging functionality into magical functions that behave unpredictably when you don't know the source code.
One other other thing: broader refactoring can often get rid of weird structures. Maybe you can encapsulate the whole (list & map of Bars)-thing into it's own class. Specialized data-structures are very often a good candidate to be moved out of a class that uses them. A class that is responsible to handle a map and a list of things could be seen as responsible for doing more than one thing -> Single responsibility principle
Related
I have the following HashMap:
HashMap<Integer, Object> ItemsData = new HashMap<Integer, Object>();
In the HashMap, I have objects of various classes, such as
ClassOne
ClassTwo
ClassThree
Each class has its own methods, attributes etc.
How do I refer to proper method, depending on the instance of the class?
For example:
ItemsData.get(5).bark() -> because item 5 is instance of class 1 which has method bark
ItemsData.get(2).jump() -> because item 2 is instance of class 2 which has method jump
ItemsData.get(6).fire() -> because item 6 is instance of class 3 which has method fire
Generally having such an untyped map in the first place is a code smell. You didn't explain enough of the underlying problem you're trying to solve to give you good advice on a nicer solution; merely to point out that this solution probably is severely suboptimal.
If you insist on using it, you can use instanceof to check if a value is of a certain type, and use a cast operator to treat it as a certain type:
Map<Integer, Object> badIdea = new ....;
...
Object secondValue = badIdea.get(1);
if (secondValue instanceof Dog) {
Dog dog = (Dog) secondValue;
dog.bark();
}
Create an interface, eg:
interface Actor {
void act();
}
And keep a collection of those:
Map<Integer, Actor> ItemsData = new HashMap<>();
Have your classes implement Actor, either directly:
public ClassOne implements Actor {
public void act() {
// make a barking noise
}
// other fields and methods
}
or indirectly:
public ClassOne implements Actor {
public void act() {
bark();
}
public void bark() {
// make a barking noise
}
// other fields and methods
}
Then invoke Actor's method instead of the original specific method:
itemsData.get(5).act();
You can also invoke all conveniently:
itemsData.forEach(Actor::act);
For a full discussion of this idea, read Liskov substitution principle.
I have a line of code:
private final Map<MyClassA<?>, MyClassB<?>> myMap = new HashMap<>();
Is there any way to define that map in a way that would tell the compiler that the ? in each case must be the same class?
Something like this?
private final <T> Map<MyClassA<T>, MyClassB<T>> myMap = new HashMap<>();
... which is not legal syntax?
It's just a self-learning question at this point.
FWIW, I want to add a method
public <T> MyClassB<T> getForA(MyClassA<T> a) {
return this.myMap.get(a);
}
But I get a compile error unless I can define myMap to insist that both the key and the value wrap the same type.
As you already figured out, you can't do that if key and value are different for different entries:
map.put(new MyClassA<Foo>(), new MyClassB<Foo>());
map.put(new MyClassA<Bar>(), new MyClassB<Bar>());
(I've taken this requirement from your comment)
What you can do is to write some helper methods, which enforce this constraint:
public <T> void put(MyClassA<T> key, MyClass<B> value) {
// Maybe check at runtime if the constraint is not validated?
map.put(key, value);
}
public <T> MyClassB<T> get(MyClassA<T> key) {
// This will produce an unchecked warning.
return (T) map.get(key);
}
As long as you only access the map through such helper methods (and don't use raw types), the constraint on the map will not be violated, which allows you to write type safe code.
The only part that is not typesafe are those helper methods, and that's where you have to be careful.
You can do something similar if you introduce one static inner class for the type you need. For example:
public class DoubleGenericTest<T> {
public static class MapHolder<Z> {
private final Map<MyClassA<Z>, MyClassB<Z>> myMap = new HashMap<>();
}
private final MapHolder<String> stringMap = new MapHolder<>();
private final MapHolder<Integer> integerMap = new MapHolder<>();
}
class MyClassA<X> {}
class MyClassB<Y> {}
This gives you the class you need to hang the type parameter onto. Maybe not ideal in every situation but it's the only thing I can think of.
Its possbile, to design a way to call different method-overloads at compile-time?
Lets say, I have this little class:
#RequiredArgsConstructor
public class BaseValidator<T> {
private final T newValue;
}
Now, I need methods that returns diffrent Objects (depends on the T).
Like this:
private StringValidator getValidator() {
return new ValidationString(newValue);
}
private IntegerValidator getValidator() {
return new Validation(newValue);
}
At the end, I want a call-hierachy that is very fluent and looks like this:
new BaseValidator("string")
.getValidator() // which returns now at compile-time a StringValidator
.checkIsNotEmpty();
//or
new BaseValidator(43)
.getValidator() // which returns now a IntegerValidator
.checkIsBiggerThan(42);
And in my "real"-case (I have a very specific way to update objects and a lot of conditions for every object and the chance of a copy-and-paste issue is very high. So the wizard enforces all developer to implement exact this way.) :
I tried diffrent ways. Complex generics inside the Validators, or play around with the generics. My last approch looks like this.
public <C> C getValidator() {
return (C) getValidation(newValue);
}
private ValidationString getValidation(String newValue) {
return new StringValidator(newValue);
}
private ValidationInteger getValidation(Integer newValue) {
return new IntegerValidation(newValue);
}
What is the trick?
//edit: I want it at compile-time and not with instanceof-checks at runtime.
What is the trick?
Not to do it like this.
Provide static factory methods:
class BaseValidator<T> {
static ValidationString getValidation(String newValue) {
return new ValidationString(newValue);
}
static ValidationInteger getValidation(Integer newValue) {
return new ValidationInteger(newValue);
}
}
class ValidationString extends BaseValidator<String> { ... }
class ValidationInteger extends BaseValidator<Integer> { ... }
Although I consider this to be odd: you are referring to subclasses inside the base class. Such cyclical dependencies make the code hard to work with, especially when it comes to refactoring, but also perhaps in initialization.
Instead, I would suggest creating a utility class to contain the factory methods:
class Validators {
private Validators() {}
static ValidationString getValidation(String newValue) {
return new ValidationString(newValue);
}
static ValidationInteger getValidation(Integer newValue) {
return new ValidationInteger(newValue);
}
}
which has no such cycles.
A really important thing to realize about generics is that it is nothing more than making explicit casts implicit (and then checking that all of these implicit casts are type-safe).
In other words, this:
List<String> list = new ArrayList<>();
list.add("foo");
System.out.println(list.get(0).length());
is just a nicer way of writing:
List list = new ArrayList();
list.add((String) "foo");
System.out.println(((String) list.get(0)).length());
Whilst <String> looks like it is part of the type, it is basically just an instruction to the compiler to squirt in a load of casts.
Generic classes with different type parameters all have the same methods. This is the specific difficulty in your approach: you can't make the BaseValidator<String>.getValidator() return something with a checkIsNotEmpty method (only), and the BaseValidator<Integer>.getValidator() return something with a checkIsGreaterThan method (only).
Well, this isn't quite true to say you can't. With your attempt involving the method-scoped type variable (<C> C getValidator()), you can write:
new BaseValidator<>("string").<StringValidator>getValidator().checkIsNotEmpty()
(assuming StringValidator has the checkIsNotEmpty method on it)
But:
Let's not mince words: it is ugly.
Worse than being ugly, it isn't type safe. You can equally write:
new BaseValidator<>("string").getValidator().checkIsGreaterThan(42)
which is nonsensical, but allowed by the compiler. The problem is that the return type is chosen at the call site: you will either have to return null (and get a NullPointerException when you try to invoke the following method); or return some non-null value and risk a ClassCastException. Either way: not good.
What you can do, however, is to make a generic validator a parameter of the method call. For example:
interface Validator<T> {
void validate(T b);
}
class BaseValidator<T> {
BaseValidator<T> validate(Validator<T> v) {
v.validate(this.value);
}
}
And invoke like so, demonstrating how you can chain method calls to apply multiple validations:
new BaseValidator<>("")
.validate(s -> !s.isEmpty())
.validate(s -> s.matches("pattern"))
...
new BaseValidator<>(123)
.validate(v -> v >= 0)
...
We decided to add more class-steps. You can go a the generic way or a way with explict types (in this examples, String). Our requirement for all updates-methods (we have many database-objects ...) are a little complicated. We want only one update-method (for each db-object), which ...
Ignore fields, that are null.
Ignore field, that are equal to "old" value.
Validate not ignored fields.
Save only, when no validation-issues occur.
To do that with many if-blocks is possbile but not really readable. And copy-paste-fails haves a high probably.
Our code look like this:
private void update(#NonNull final User.UpdateFinalStep params) {
UpdateWizard.update(dbUserService.get(params.getId())
.field(params.getStatus())
.withGetter(DbUser::getAccountStatus)
.withSetter(DbUser::setAccountStatus)
.finishField()
.field(Optional.ofNullable(params.getUsername())
.map(String::toLowerCase)
.orElse(null))
.withGetter(DbUser::getUsername)
.withSetter(DbUser::setUsername)
.beginValidationOfField(FieldName.USERNAME)
.notEmptyAndMatchPattern(USERNAME_PATTERN, () -> this.checkUniqueUsername(params.getUsername(), params.getId()))
.endValidation()
.field(params.getLastName())
.withGetter(DbUser::getLastname)
.withSetter(DbUser::setLastname)
.beginValidationOfField(FieldName.USER_LASTNAME)
.notEmptyAndMatchPattern(LAST_NAME_PATTERN)
.endValidation()
.field(params.getFirstName())
.withGetter(DbUser::getFirstname)
.withSetter(DbUser::setFirstname)
.beginValidationOfField(FieldName.USER_FIRSTNAME)
.notEmptyAndMatchPattern(FIRST_NAME_PATTERN)
.endValidation()
.save(dbUserService::save);
}
This is very readable and allows to add new field in a very simple way. With the generics, we dont give the "stupid developer" a chance to do an misstake.
As you can see in the image, accountStatus and username points to different classes.
At the end, we can use in a very fluent way the update-method:
userService.startUpdate()
.withId(currentUserId)
.setStatus(AccountStatus.INACTIVE)
.finallyUpdate();
I have a generic class in java defined as:
public static class KeyCountMap<T>
{
private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
// ... rest of the properties...
public KeyCountMap()
{ }
#SuppressWarnings({ "unchecked", "rawtypes" })
public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException
{
map = mapType.newInstance();
}
//... rest of the methods...
}
I have defined same class in .NET as:
public static class KeyCountMap<T>
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
{
obj = new T(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
}
And then a method is defined to sort map of type KeyCountMap<T> by value in the descending order . The method is defined as:
public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());
// whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>
_list = _list.OrderByDescending(_x => _x.Value).ToList();
KeyCountMap<T> _result = new KeyCountMap<T>();
foreach (KeyValuePair<T, MutableInt> _entry in _list)
{
_result.Put(_entry.Key, _entry.Value);
}
return _result;
}
How can I get corrected the class defined in .NET ?
I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:
#SuppressWarnings({ "unchecked", "rawtypes" })
You're using this because you're creating a non-parameterized instance of Map.
In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.
Let's see your C# code:
public static class KeyCountMap<T>
A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.
In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
Why the void return type, isn't this a constructor?
In C#, constructors can't be generic. You probably want a Type.
Your C# code just doesn't make sense, so here's what you could do:
public KeyCountMap(Type dictionaryType)
{
if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
{
throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
}
map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
}
}
We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.
It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.
You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.
This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.
In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class<T> at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.
There are two problems. First, you need to tell the compiler that T has a parameterless constructor, so you can call new T(). You can do that by providing the new() argument to the class definition.
You also have to tell the compiler that T is actually the dictionary you are trying to assign, so we have to extend the class a little more:
public class KeyCountMap<K>
{
private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
// ... rest of properties...
Note that K is the key type of the dictionary, which you didn't specify yet.
Second, the T in your method can be another T than in your class. Omitting that will do the trick:
public void Map()
{
var obj = new Dictionary<K, MutableInt>(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
Maybe this is what you want?
public class KeyCountMap<T>
where T : new()
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public KeyCountMap(T obj)
{
obj = new T();
map = (Dictionary<T, MutableInt>)(object)obj;
}
}
Take, for example, immutability. How could I modify an object to indicate that it has been made immutable already and need not be wrapped again?
Let us assume we do not want to use reflection to scan for setters as that would be inefficient and insufficient.
Example:
// Deliberately chosing lowercase because it is a system attribute.
interface immutable {
// Nothing in here I can think of.
}
// immute - have I invented a new word?
// What can I do with the return type to indicate immutability?
public static <T> List<T> immute(List<T> list) {
// If it's not an immutable
if (!(list instanceof immutable)) {
// Make it so - how can I stamp it so?
return Collections.<T>unmodifiableList(list);
}
// It is immutable already.
return list;
}
Further playing with the idea produced this foul solution - it is horrible and almost any other trick would be better but I felt I should post. Please please find a better solution:
public class Test {
// Deliberately chosing lowercase because it is a system attribute.
interface immutable {
// Nothing in here I can think of.
}
// immute - have I invented a new word?
// What can I do with the return type to indicate immutability?
public static <T> List<T> immute(List<T> list) {
// If it's not an immutable
if (!(list instanceof immutable)) {
// Make it so - how can I stamp it so?
return Hacker.hack(Collections.<T>unmodifiableList(list),
List.class,
immutable.class);
}
// It is immutable already - code DOES get here.
return list;
}
public void test() {
System.out.println("Hello");
List<String> test = new ArrayList<>();
test.add("Test");
test("Test", test);
List<String> immutableTest = immute(test);
test("Immutable Test", immutableTest);
List<String> immutableImmutableTest = immute(immutableTest);
test("Immutable Immutable Test", immutableImmutableTest);
}
private void test(String name, Object o) {
System.out.println(name + ":" + o.getClass().getSimpleName() + "=" + o);
}
public static void main(String args[]) {
new Test().test();
}
}
class Hacker {
// Hack an object to seem to implement a new interface.
// New interface should be instanceof testable.
// Suggest the additional type is an empty interface.
public static <T> T hack(final Object hack,
final Class<T> baseType,
final Class additionalType) {
return (T) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{baseType, additionalType},
new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Always invoke the method in the hacked object.
return method.invoke(hack, args);
}
});
}
}
If the check will be done on the same location, you could use a set or map, where you put all your wrapped objects, and check them later on in almost constant time. To avoid memory leaks, you could wrap them using weak references .
If the introduction of AOP is a (rather heavyweight) option, you could solve your problem using inter type declarations via AspectJ. This way, you could just add a private member with the reference to the corresponding wrapped instance to the Collection interface, if I remember correctly something like this:
aspect Unmodifieable {
private Collection java.util.Collection.unmofifieableWrapper = null;
public Collection java.util.Collection.getUnmodifieable() {
if (unmofifieableWrapper == null) {
unmofifieableWrapper = somehowRetrieveUnmodifieableCollection(this);
}
return unmofifieableWrapper;
}
}
You can do this with naming conventions in your classes.
interface MyObject;
class MyMutableObject implements MyObject;
class MyImmutableObject implements MyObject;
In my current project, I do something similar. I have an interface that needs to have a setter, but one of the implementing classes is immutable. When you call its setter it throws an Exception (it's setter should never be called, but it's there just to be safe).
The "information" you're looking for is more for the programmer than the compiler, so you don't need a language implemented "stamp".
The Collections.unmodifiable* methods return subtypes of UnmodifiableCollection so you could check UnmodifiableCollection.class.isAssignableFrom(list) then test the concrete types.
Without using instrumentation, I think you're stuck checking types.