Given the following code:
String s = "dirty";
for (Action action : actions) {
s = doAction(s, action);
}
...where Actions can be a cleaning operation on the string such as removing illegal chars or removing a duplicate word.
Is there a way to write this more elegantly to handle the call without reassigning the string?
I don't think you can avoid reassigning the string as you need the updated value in each iteration.
As for:
Is there a way to write this more elegantly
Using the streams API, you could do:
String result = actions.stream() // or Arrays.stream(actions)
.reduce("dirty", (s, action ) -> doAction(s, action),
(e, a) -> {throw new RuntimeException("un-implemented");});
Although it's arguably not as readable as your solution.
A recursive way to write it would be something like this:
public static void main(String[] args) {
List<Action> actions = .. //your list of Actions
String s = doActions("dirty", actions);
}
private static String doActions(String s, List<Action> actions) {
if(actions.isEmpty()) {
return s;
} else {
// apply the first Action
Action action = actions.remove(0);
String newString = doAction(s, action);
// recursively call with the new String and the remaining actions
return doActions(newString, actions);
}
}
But as you can see, you still get a string creation/assignement in the doActions method. This is due to the fact that String is immutable and can't be modified.
If you are just looking for a recursive way to write it then that could do. If you really want to get rid of the new String creation, you need to use a StringBuilder, as Jacob G suggested. With a signature such as
void doAction(StringBuilder sb, Action action)
You can avoid reassigning s by making it a field
public class SActions {
private String s;
SActions(String s){this.s = s;}
public void doAction(Action action){ /* apply action to s */}
public String getString() { return s; }
public static void main(String[] args) {
SActions sActions = new SActions("abc");
sActions.doAction(anAction);
System.out.println(sActions.getString());
}
}
You could also add a method to accept a collection of Actions:
public void doAction(Collection<Action> actions) {
for (Action action : actions) {
doAction(action);
}
}
To make the object reusable, add a setter:
public SActions setString(String s) {
this.s = s;
return this;//for convenience, so you can chain invocation
}
Note that the setter return this for more convenient invocation:
SActions sActions = new SActions(); //requiers standard constructor
sActions.setString("abc").doAction(anAction);
If it is more or less elegant' it is certainly arguable.
Related
I have a list of methods within my class. And then want to have input string array, where the user can choose which methods they want to run. We are running expensive insurance calculations. And have over say eg 20 methods. Is there a way to conduct this without do an if check on each? maybe with reflection or interface?
#Override
public void ProductTest(ProductData productData, String[] methodNames) {
public void methodA(ProductData productData){...};
public void methodB(ProductData productData){...};
public void methodC(ProductData productData){...};
public void methodD(ProductData productData){...};
public void methodE(ProductData productData){...};
}
I am willing to change the Array into a different ObjectType if needed, to execute properly. Using SpringBoot, has it has a library of utility classes.
Use a Map<String, Consumer<ProductData>>, not separate method handles. Main reason - reflection is slow and dangerous when given user "input"
Use map.get(input).accept(product) to call it.
https://docs.oracle.com/javase/8/docs/api/index.html?java/util/function/Consumer.html
Example
Map<String, Consumer<ProductData>> map = new HashMap<>();
map.put("print_it", System.out::println);
map.put("print_id", data -> System.out.println(data.id));
map.put("id_to_hex", data -> {
int id = data.getId();
System.out.printf("0x%x%n", id);
});
ProductData data = new ProductData(16);
map.get("print_it").accept(data);
map.get("print_id").accept(data);
map.get("id_to_hex").accept(data);
Outputs
ProductData(id=16)
16
0x10
If you are planning on chaining consumers using andThen, you'd be better having an Optional<ProductData>, and using a Function<ProductData, ProductData> with Optional.map()
One way to do it is via reflection. You can iterate over methods in the class object and look for ones to run by name. Here's some example code--this would print out a list of names the user could type in:
myObject.getClass().getDeclaredMethods().each((method)->System.out.println(method.getName()))
And this is how you would call it once the user had made a selection:
productTest.getDeclaredMethods().each((method)->
if(method.getName().equals(userSelectedName))
method.invoke(productTest, productData)
)
The ONLY advantage to this approach is that you don't have to maintain a second structure (Switch, Map, etc...) and add to it every time you add a new method. A personality quirk makes me unwilling to do that (If adding something one place forces you to update a second, you're doing it wrong), but this doesn't bother everyone as much as it bothers me.
This isn't dangerous or anything, if you don't have a method in the class it can't call it, but if you are relying on users "Typing", I'd suggest listing out the options and allowing a numeric selection--or using reflection to build a map like OneCricketeer's.
I've used this pattern to write a testing language and fixture to test set-top TV boxes, it was super simple to parse a group of strings, map some to methods and other to parameters and have a very flexible, easily extensible testing language.
The method object also has a "getAnnotation()" which can be used to allow more flexible matching in the future.
You can use method invocation.
For example, you can have two methods, first one will loop through your methodNames array and call the second method:
public void callPassedMethods(ProductData productData, String[] methodNames) {
for (String m : methodNames) {
callMethod(productData, m)
}
}
And the second method will actually find a method in your class that matches the string passed and invoke it:
public void callMethod(ProductData productData, String methodName) {
try {
ClassName yourObj = new ClassName(); // Class where your methods are
Method method = yourObj.getClass().getDeclaredMethod(methodName, ProductData.class);
method.invoke(yourObj, productData);
} catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// handle exceptions
}
}
Or, you can always use the good old switch statement:
for (String m : methodNames) {
switch (m) {
case "methodA":
methodA();
break;
case "methodB":
methodB();
break;
// ... continue with as many cases as you need
}
}
If you go with the reflection route, you don't really want to expose your method names to the end users. They might not be end user-friendly, and if they are, there is no reason for users to know this information and there might be methods, which are not supposed to be invoked by users. I would use custom annotations to build more flexible matching.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface UserChoice {
String userFriendlyOption();
int optionNumber();
}
optionNumber will be used for matching the method to invoke, userFriendlyOption is some user friendly text.
Annotate only the methods, supposed to be used by users.
#RequiredArgsConstructor
public class ProductData {
private final double data;
#UserChoice(userFriendlyOption = "see result for option a", optionNumber = 1)
public void methodA() {
System.out.println(data + 1);
}
#UserChoice(userFriendlyOption = "see result for option b", optionNumber = 2)
public void methodB() {
System.out.println(data + 2);
}
#UserChoice(userFriendlyOption = "see result for option c", optionNumber = 3)
public void methodC() {
System.out.println(data);
}
public void methodNotForUser() {
System.out.println("Should not be seen by users");
}
}
Like this methodNotForUser() can't be invoked by end users.
Simplified matcher might look like this.
#RequiredArgsConstructor
public class ProductTester {
private final ProductData data;
private Map<Integer, MethodData> map;
public void showOptions() {
if (this.map == null) {
this.map = new HashMap<>();
for (Method method : this.data.getClass().getMethods()) {
UserChoice userChoice = method.getAnnotation(UserChoice.class);
if (userChoice != null) {
String userRepresentation = userChoice.optionNumber() + " - " + userChoice.userFriendlyOption();
this.map.put(userChoice.optionNumber(), new MethodData(userRepresentation, method));
}
}
}
this.map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.println(entry.getValue().getUserRepresentation()));
}
public void showOptionResult(int choice) {
MethodData methodData = this.map.get(choice);
if (methodData == null) {
System.out.println("Invalid choice");
return;
}
System.out.println("Result");
try {
methodData.getMethod().invoke(this.data);
} catch (IllegalAccessException | InvocationTargetException ignore) {
//should not happen
}
}
}
MethodData is simple pojo with the sole purpose to not recalculate user representation.
#RequiredArgsConstructor
#Getter
public class MethodData {
private final String userRepresentation;
private final Method method;
}
Short main to illustrate the idea and play around:
public class Temp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Write initial value");
double data = scanner.nextDouble();
ProductData myData = new ProductData(data);
ProductTester tester = new ProductTester(myData);
tester.showOptions();
System.out.println("Write option number");
int userChoice = scanner.nextInt();
tester.showOptionResult(userChoice);
}
}
I have multiple Optionals that must be mapped to a POJO. Is there a better alternative than the following?
class SimplePojo {
private String stringField;
private Integer integerField;
// All args. constructor, getter, setter
}
Optional<String> stringOptional = ...
Optional<Integer> integerOptional = ...
Optional<SimplePojo> simplePojoOptional = stringOptional.flatMap(
string -> integerOptional.map(integer -> new SimplePojo(string, integer)))
I have reduced the problem to 2 Optionals in the above example to keep it short. But I actually have 3 Optionals with more on the way. I am afraid the last line can easily become unwieldy soon.
Please note: Use of functional frameworks like Vavr or Functional Java is not an option for me.
How about using a Builder ?
class SimplePojo {
public static class Builder {
private String stringField;
public Builder withStringField(String str) {
this.stringField = str;
return this;
}
// and other "with" methods...
public Optional<SimplePojo> build() {
if (stringField == null || anotherField == null /* and so forth */) {
return Optional.empty();
} else {
return Optional.of(new SimplePojo(this));
}
}
}
private final String stringField;
/* private constructor, so client code has to go through the Builder */
private SimplePojo(Builder builder) {
this.stringField = builder.stringField;
// etc.
}
}
Then you could use it as follows:
SimplePojo.Builder builder = new SimplePojo.builder();
optionalStringField.ifPresent(builder::withStringField);
// etc.
return builder.build();
I do not see any advantage from pursuing the functional style this way here. see three options:
ONE: If you can alter the SimplePojo class and if this scenario is a common one, you might consider to add a factory method to the SimplePojo:
class SimplePojo {
public static Optional<SimplePojo> of(final Optional<String> stringField, final Optional<Integer> integerField) {
if (stringField.isPresent() && integerField.isPresent()) {
return new SimplePojo(stringField.get(), integerField.get());
else
return Optional.empty();
}
}
TWO: If you cannot alter the SimplePojo, you might want to create this as a utility method somewhere else. If you need this pattern only in one class, make the method private in this class!
THREE: If you need to do this only once or twice, I would prefer the if...then construction from the first option over the functional notation you used for the sake of readability:
final Optional<SimplePojo> simplePojoOptional;
if (stringField.isPresent() && integerField.isPresent()) {
simplePojoOptional = new SimplePojo(stringField.get(), integerField.get());
else
simplePojoOptional = Optional.empty();
I need to do a lot of different preprocessing of some text data, the preprocessing consists of several simple regex functions all written in class Filters that all take in a String and returns the formatted String. Up until now, in the different classes that needed some preprocessing, I created a new function where I had a bunch of calls to Filters, they would look something like this:
private static String filter(String text) {
text = Filters.removeURL(text);
text = Filters.removeEmoticons(text);
text = Filters.removeRepeatedWhitespace(text);
....
return text;
}
Since this is very repetitive (I would call about 90% same functions, but 2-3 would be different for each class), I wonder if there are some better ways of doing this, in Python you can for example put function in a list and iterate over that, calling each function, I realize this is not possible in Java, so what is the best way of doing this in Java?
I was thinking of maybe defining an enum with a value for each function and then call a main function in Filters with array of enums with the functions I want to run, something like this:
enum Filter {
REMOVE_URL, REMOVE_EMOTICONS, REMOVE_REPEATED_WHITESPACE
}
public static String filter(String text, Filter... filters) {
for(Filter filter: filters) {
switch (filter) {
case REMOVE_URL:
text = removeURL(text);
break;
case REMOVE_EMOTICONS:
text = removeEmoticons(text);
break;
}
}
return text;
}
And then instead of defining functions like shown at the top, I could instead simply call:
filter("some text", Filter.REMOVE_URL, Filter.REMOVE_EMOTICONS, Filter.REMOVE_REPEATED_WHITESPACE);
Are there any better ways to go about this?
Given that you already implemented your Filters utility class you can easily define a list of filter functions
List<Function<String,String>> filterList = new ArrayList<>();
filterList.add(Filters::removeUrl);
filterList.add(Filters::removeRepeatedWhitespace);
...
and then evaluate:
String text = ...
for (Function<String,String> f : filterList)
text = f.apply(text);
A variation of this, even easier to handle:
Define
public static String filter(String text, Function<String,String>... filters)
{
for (Function<String,String> f : filters)
text = f.apply(text);
return text;
}
and then use
String text = ...
text = filter(text, Filters::removeUrl, Filters::removeRepeatedWhitespace);
You could do this in Java 8 pretty easily as #tobias_k said, but even without that you could do something like this:
public class FunctionExample {
public interface FilterFunction {
String apply(String text);
}
public static class RemoveSpaces implements FilterFunction {
public String apply(String text) {
return text.replaceAll("\\s+", "");
}
}
public static class LowerCase implements FilterFunction {
public String apply(String text) {
return text.toLowerCase();
}
}
static String filter(String text, FilterFunction...filters) {
for (FilterFunction fn : filters) {
text = fn.apply(text);
}
return text;
}
static FilterFunction LOWERCASE_FILTER = new LowerCase();
static FilterFunction REMOVE_SPACES_FILTER = new RemoveSpaces();
public static void main(String[] args) {
String s = "Some Text";
System.out.println(filter(s, LOWERCASE_FILTER, REMOVE_SPACES_FILTER));
}
}
Another way would be to add a method to your enum Filter and implement that method for each of the enum literals. This will also work with earlier versions of Java. This is closest to your current code, and has the effect that you have a defined number of possible filters.
enum Filter {
TRIM {
public String apply(String s) {
return s.trim();
}
},
UPPERCASE {
public String apply(String s) {
return s.toUpperCase();
}
};
public abstract String apply(String s);
}
public static String applyAll(String s, Filter... filters) {
for (Filter f : filters) {
s = f.apply(s);
}
return s;
}
public static void main(String[] args) {
String s = " Hello World ";
System.out.println(applyAll(s, Filter.TRIM, Filter.UPPERCASE));
}
However, if you are using Java 8 you can make your code much more flexible by just using a list of Function<String, String> instead. If you don't like writing Function<String, String> all the time, you could also define your own interface, extending it:
interface Filter extends Function<String, String> {}
You can then define those functions in different ways: With method references, single- and multi-line lambda expressions, anonymous classes, or construct them from other functions:
Filter TRIM = String::trim; // method reference
Filter UPPERCASE = s -> s.toUpperCase(); // one-line lambda
Filter DO_STUFF = (String s) -> { // multi-line lambda
// do more complex stuff
return s + s;
};
Filter MORE_STUFF = new Filter() { // anonymous inner class
// in case you need internal state
public String apply(String s) {
// even more complex calculations
return s.replace("foo", "bar");
};
};
Function<String, String> TRIM_UPPER = TRIM.andThen(UPPERCASE); // chain functions
You can then pass those to the applyAll function just as the enums and apply them one after the other in a loop.
I'm reading from a text file, like so:
while ((line = br.readLine()) != null) {
String[] a = line.split("\\: ");
key = a[0];
action = a[1];
gameKeys.add(key, action);
}
where the file would be something like
SPACE: FIRE_ACTION
E: USE_ACTION
This part works, key and action are both what I want.
gameKeys is a Map declared like so:
private static Map<Keyboard.Key, Action> gameKeys = new HashMap<>();
Keyboard.Key has fields such as SPACE, A, RETURN, etc.
Action is an interface, that holds other actions; those actions have a toString() method that returns the action, e.g. new FireAction.toString() returns FIRE_ACTION.
Example of an Action:
public class FireAction implements Action {
#Override
public void execute() {
System.out.println("Fire key pressed!");
}
#Override
public String toString() {
return "FIRE_ACTION";
}
}
So, I'm trying to turn the file's components into objects, like if key was "SPACE" and action was "FIRE_ACTION", then, after the add method is performed, gameKeys would have <Keyboard.Key.SPACE, new FireAction()>
Is there anyway I can do this?
You could try this:
Save your Action classes in a Map<String, Class<? extends Action>>
Read the Key -> Action bindings from the file
Resolve the string action to an actual Action object via the map
Example:
public class Main {
private static final Map<Keyboard.Key, Action> gameKeys = new HashMap<>();
private static final Map<String, Class<? extends Action>> actions = new HashMap<>();
static {
actions.put(FireAction.NAME, FireAction.class);
actions.put(WalkAction.NAME, WalkAction.class);
}
public static void main(String[] args) {
// read from file etc.
try {
// e.g. found SPACE : FIRE_ACTION
gameKeys.put(Keyboard.Key.SPACE, actions.get("FIRE_ACTION").newInstance());
// e.g. found A : WALK_ACTION
gameKeys.put(Keyboard.Key.A, actions.get("WALK_ACTION").newInstance());
} catch (IllegalAccessException | InstantiationException ex) {
ex.printStackTrace();
}
}
}
public class FireAction implements Action {
public static final String NAME = "FIRE_ACTION";
#Override
public void execute() {
System.out.println("Fire key pressed!");
}
#Override
public String toString() {
return NAME;
}
}
Sure
Object keyObj = key, actionObj;
if (key.equals("SPACE")) keyObj = Keyboard.Key.SPACE;
if (action.equals("FIRE_ACTION")) actionObj = new FireAction());
You can use a Map<String, ...> as an alternative to using 'if's if you have a lot of cases
You can't achieve what you have asked directly - because then Java would have to create ALL the classes it can create(some have non-default constructors or even private), and call their toString() method (which may have side-effects in general case).
So anyway you'll have to create registry with all actions(preferrable way), or you can try to use reflection to create Actions in runtime.
I am relatively inexperienced with java & generics, so please excuse me if this is a stupid question.
I have 3 very similar helper methods called verifyTextualSort, verifyNumericSort and verifyDateSort.
The 3 methods follow the same pattern with only a slight difference in them:
private boolean verifyTextualSort(...) {
ArrayList<String> list = new ArrayList<String>();
// Do common stuff with the list
// Do textual-specific stuff
// Do common stuff with the list
}
private boolean verifyNumericSort(...) {
ArrayList<Integer> list = new ArrayList<Integer>();
// Do common stuff with the list
// Do Numeric-specific stuff
// Do common stuff with the list
}
Is there some way I can combine them into one method, passing somehow the type (Integer, String, Date) as a parameter? I have to be able to know which is the type from inside the method so that I can do the correct specific stuff.
You need three method for the specific stuff. However for the common stuff you can create a common method they both call.
private boolean verifyNumericSort(...) {
List<Integer> list = new ArrayList<Integer>();
commonStuff1(list);
// Do Numeric-specific stuff
commonStuff2(list);
}
You could pass a Class as a parameter, if that is what you want (as you said, passing the type as a parameter):
public <T> void test(List<T> l, T t, Class<T> c) {
System.out.println(c.getName());
System.out.println(l.get(0).getClass().getName());
System.out.println(t.getClass().getName());
}
All the sysouts above will print out the name of the class, so you'll be able to choose which one suits you the best.
You can't do that by introspection using the Generics because of type erasure. But if the list is not empty, you can check the type of the first element and then invoke appropriate method.
since you have 3 fields you can do this..
class A
{
private Date date = null;
private Integer int = null;
private String text = null;
//add getters and setters for these fields
}
and now pass this class Object as an arguement to that method
public boolean verify(A a){
a.getDate();
a.getInt()
//etc and do your stuff
}
You need generics and refactoring:
private boolean verifyTextualSort(List<String> strings) {
commonStuffA(strings);
// Do textual-specific stuff
commonStuffB(strings);
return true; // ?
}
private boolean verifyNumericSort(List<Integer> ints) {
commonStuffB(ints);
// Do Numeric-specific stuff
commonStuffB(ints);
return true; // ?
}
private void commonStuffA(List<?> things) { // This method accept a list of anything
// Do common stuff A with the list
}
private void commonStuffB(List<?> things) { // This method accept a list of anything
// Do common stuff B with the list
}
private void someCallingMethod() {
List<String> strings = new ArrayList<String>();
verifyTextualSort(strings);
List<Integer> ints = new ArrayList<Integer>();
verifyTextualSort(ints);
}
I think you could possibly do something similar to this:
public <T extends Object> boolean verify(T t)
{
if(!(t==null))
{
if(t instanceof Date)
{
//Do date verify routine
return true;
}
else if(t instanceof String)
{
//Do String verify routine
return true;
}
else
{
//Do default verify routine which could be Integer
return true;
}
}
return false;
}
NOTE:
This is not tested.
As others have mentioned, you can't do that with generics because of type erasure (see the other answers for a link to type erasure). I believe you can get a reasonable solution (without instanceof) with polymorphism. Here is an example:
public class VerifySort
{
public static void main(String[] args)
{
VerifySort verifySort = new VerifySort();
Date testDate = new Date();
Integer testInteger = 17;
String testString = "Blammy";
verifySort.verify(testString);
verifySort.verify(testInteger);
verifySort.verify(testDate);
}
private boolean verify(Date parameter)
{
SimpleDateFormat dateFormat = new SimpleDateFormat();
System.out.print("Date parameter: ");
System.out.println(dateFormat.format(parameter));
return true;
}
private boolean verify(Integer parameter)
{
System.out.print("Integer parameter: ");
System.out.println(parameter);
return true;
}
private boolean verify(String parameter)
{
System.out.print("String parameter: ");
System.out.println(parameter);
return true;
}