hello how do I call a method taking an interface as a parameter from the main ?
The code in the main is an example of what I want to achieve but by calling the method map now
What do I write in my map method and how do I call it in the main ? Thank you
What I want to achieve :
StringTransformation addBlah = (e) -> {
e += "boo";
return e;
};
System.out.println(addBlah.transf("Hello")); // prints Helloboo
public class Main{
public static void main(String[] args) {
String a = hello;
// How do I modify the string a by calling map ?
}
void map(StringTransformation t) {
// What do I write ??
}
}
public interface StringTransformation {
String transf(String s);
}
You want to modify a String with a given StringTransformation so you need to pass both of them to the map method. Also you can turn addBlah in a more simple lambda :
public static void main(String[] args) {
StringTransformation addBlah = (e) -> e + "boo";
String str = "Hello";
System.out.println(str); // Hello
str = map(addBlah, str);
System.out.println(str); // Helloboo
}
static String map(StringTransformation t, String argument) {
return t.transf(argument);
}
You cannot call map inside the static main method. You must make map a static method as well if you want to do that. Also we can't help you with what to put inside your map function if you don't tell us what it should do.
public static void main(String[] args) {
String string = "Hello";
// you can call `mapBoo` like normal here
string = mapBoo(string);
System.out.println(string);
List<String> strings = Arrays.asList("Hello", "this", "is", "a", "test");
// or you can pass mapBoo into the stream.map method since map fits the method signature
List<String> mappedStrings = strings.stream().map(Main::mapBoo)
.collect(Collectors.toList());
for (String mappedString : mappedStrings)
System.out.println(mappedString);
}
static String mapBoo(String s) {
return s + "boo";
}
Related
Here is Demo class
public class Demo {
int i;
String s;
}
I have an instance of Demo:
Demo demo = new Demo(1, "hello");
How can I get demo field values as array of Object like:
Object[] {1, "hello"};
Updated:
For new Object[] {demo.i, demo.s} I need know fields from Demo, however I need a general way to get Object array for any class that has primitive fields and/or simple fields.
you will need to make it yourself indeed. To get it how you showed, you will want a getter method in your object
public class Demo(){
int i;
String s;
public Demo(){
//constructor
}
public Object[] getDemo{
return new Object[] {i, s};
}
}
As stated in the comments, you can do it via reflection quite easily:
public static Object[] getFieldValues(Object o) {
return Arrays.stream(o.getClass().getDeclaredFields())
.map(field -> {
try {
return field.get(o);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
})
.toArray();
}
public static void main(String[] args) {
class Demo {
int i;
String s;
}
Demo d = new Demo();
d.i = 1;
d.s = "hello";
Object[] fieldValues = getFieldValues(d);
System.out.println(Arrays.toString(fieldValues));
}
However, also as stated in the comments, this might be an "X-Y problem" and there may be better solutions to what you are actually looking to achieve.
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.
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 have a Java method which accepts arguments in ellipses format. This method in turns call an api which again accepts parameters in ellipses format:
public void myMethod(String a, String... listOfParam){
//Method Signature of anotherAPI is anotherAPI(String input, Object ... listOfParams)
//I call anotherAPI method as described below.
String result = anotherAPI(a, listOfParam);
}
However, when I pass listOfParams as arguments, I get UnsupportedOperationException.
Please let me know the correct approach in this case.
Edit
I am calling AmazonDynamoDB Java API's
(http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html?index-all.html) addHashOnlyPrimaryKeys method :
The client method is as below :
public static List<Item> getAllItems(String tableName,String primaryKeyName, String ... listOfKeys){
List<Item> itemList = null;
System.out.println(listOfKeys.toString());
TableKeysAndAttributes tkaa = new TableKeysAndAttributes(tableName);
tkaa.addHashOnlyPrimaryKey(primaryKeyName, listOfKeys);
BatchGetItemOutcome outcome = dynamoDB.batchGetItem(tkaa);
itemList = outcome.getTableItems().get(tableName);
return itemList;
}
I testing this method as :
List<Item> listOfItems = AmazonDynamoDBUtil.getAllItems("myTable","data","1","2","3","4");
Here is data is of type String.
However, the exception which I am getting is :
Exception in thread "main" java.lang.UnsupportedOperationException: value type: class [Ljava.lang.String;
at com.amazonaws.services.dynamodbv2.document.internal.InternalUtils.toAttributeValue(InternalUtils.java:221)
at com.amazonaws.services.dynamodbv2.document.internal.InternalUtils.toAttributeValueMap(InternalUtils.java:535)
at com.amazonaws.services.dynamodbv2.document.internal.InternalUtils.toAttributeValueMap(InternalUtils.java:547)
at com.amazonaws.services.dynamodbv2.document.internal.BatchGetItemImpl.doBatchGetItem(BatchGetItemImpl.java:84)
at com.amazonaws.services.dynamodbv2.document.internal.BatchGetItemImpl.batchGetItem(BatchGetItemImpl.java:58)
at com.amazonaws.services.dynamodbv2.document.DynamoDB.batchGetItem(DynamoDB.java:154)
at awsdynamodb.AmazonDynamoDBUtil.getAllItems(AmazonDynamoDBUtil.java:63)
Please let me know what can be wrong with this approach.
This is working:
public class Main {
public static void main(String[] args) {
myMethod("test 1");
myMethod("test 2", "a");
myMethod("test 3", "a", "b", "c");
}
public static void myMethod(String a, String... listOfParam) {
anotherAPI(a, listOfParam);
}
private static void anotherAPI(String a, String... listOfParam) {
StringBuilder sb = new StringBuilder();
for (String p : listOfParam) {
sb.append(p);
sb.append(", ");
}
System.out.println(a + ": " + sb.toString());
}
}
produces the expected result:
test 1:
test 2: a,
test 3: a, b, c,
From a Java point of view listOfParam as String... is a String[] array.
The following code runs fine for me, albeit with a warning (which you can get rid of by casting the second parameter of the call to anotherAPI() to Object[]):
public class Test
{
public static String anotherAPI(final String a, final Object... listOfParam)
{
for (final Object param : listOfParam)
System.out.println(param);
return "Test";
}
public static void main(final String[] args)
{
myMethod("a", "This", "is", "a", "test");
}
public static void myMethod(final String a, final String... listOfParam)
{
final String result = anotherAPI(a, listOfParam);
System.out.println(result);
}
}
with the output:
This
is
a
test
Test
I think the implementation of anotherAPI() doesn't allow for what you are trying to do.
The API doesn't support that method call (hence the unsupported exception). Nothing to do with ellipsis. Don't call that method, it won't work.
Sorry guys , it seems I was calling addHashOnlyPrimaryKey instead of addHashOnlyPrimaryKeys :)
I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1