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
Related
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";
}
Every time I call the method inserimentoVoto to add elements in a list contained in the object Studente, the data is overwritten I know it's easy but I just started to code.
public class Run {
public static void main(String[] args) {
Gestione g = new Gestione();
Studente s = new Studente();
g.inserimentoVoto(s);
}
}
This is the method
public void inserimentoVoto(Studente s) {
Voto v = new Voto();
System.out.println("Insert value");
v.setVoto(scanner.next());
System.out.println("Insert name");
v.setMateria(scanner.next());
v.setDataVoto(new Date());
s.setListaVoti(new ArrayList<Voto>());
s.getListaVoti().add(v);
}
s.setListaVoti(new ArrayList<Voto>());
You are creating a new ArrayList everytime
The above line should be only done once in the Studente class.
public class Studente
{
private ArrayList<Voto> arr = new ArrayList<Voto>();
... Other data ...
public ArrayList<Voto> getListaVoti()
{
return arr;
}
... Other methods ...
}
You do not need a setListaVoti at all - because it's done only once.
In the inserimentoVoto method, you only need
s.getListaVoti().add(v);
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 :)
While reading online, I came across the following:
public interface UnaryFunction<T>
{
T apply(T arg);
}
.......
private static UnaryFuntion<Object> ID_FUNC = new UnaryFunction<Object>
{
Object apply(Object arg)
{
return arg;
}
};
public static <T> UnaryFunction<T> idFunction()
{
return (UnaryFunction<T>) ID_FUNC;
}
In main:
public static void main(String[] args)
{
String[] strings = {"Peter", "Paul", "Mary"};
UnaryFunction<String> names = idFunction();
for(String s : strings)
{
System.out.println(names.apply(s));
}
Number[] numbers = {1, 2.0, 3L};
UnaryFunction<Number> nums = idFunction();
for(Number n : numbers)
{
System.out.println(nums.apply(n));
}
}
My question is, why do we need a generic interface here?
Would simply the following suffice:
public interface UnaryFunction
{
Object apply(Object arg); //Object as return type and argument type, instead.
}
? What is the need here to use generics?
And, what is actually a generic singleton factory? What is it good for?
Thanks.
The generic singleton factory is the idFunction in your example. Without it you would have a choice between two ugly alternatives, either require a cast wherever you use it, like this:
public class ExampleWithoutGenericSingletonFactory {
static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
public Object apply(Object arg) {
return arg;
}
};
public static void main(String[] args) {
BigDecimal b = new BigDecimal("1234.1241234");
BigDecimal b1 = (BigDecimal)(ID_FUNC.apply(b)); // have to cast here >_<
System.out.println("engineeringstring val of b1 = "
+ b1.toEngineeringString());
}
}
or make separate implementations for every type you want to support:
public static UnaryFunction<String> ID_FUNC_STRING = new UnaryFunction<String>() {
public String apply(String arg) {
return arg;
}
};
public static UnaryFunction<Number> ID_FUNC_NUM = new UnaryFunction<Number>() {
public Number apply(Number arg) {
return arg;
}
};
public static UnaryFunction<BigDecimal> ID_FUNC_DECIMAL = new UnaryFunction<BigDecimal>() {
public Number apply(BigDecimal arg) {
return arg;
}
};
giving you some ugly verbose cut-n-pasted code with a different name for every type that you have to keep straight. But since you know it's a pure function and the types get erased, you can have only one implementation (ID_FUNC) and have the singleton factory idFunction return it.
You would use this for cases where you have one function implementation that you want to be able to specify different types on, where the implementation is stateless.
The example could be better, since it only calls toString on the objects returned from the function call there's no demonstrated benefit from the factory. If the example showed using type-specific methods on the objects returned then the benefit might be more apparent.
An unchecked cast warning comes up when you do this, but it's safe to suppress it (which is what Joshua Bloch advises).
This could well be a stupid question, but I'm new to Java, so...
I've currently got some code where currently this is being used
clazz.asSubclass(asSubclassOfClass).getConstructor().newInstance()
I need to pass some arguments to the contructort so I want to change it to: clazz.asSubclass(asSubclassOfClass).getConstructor(params).newInstance(args)
What I don't understand is what I need to pass in as params and what I need to pass in as args.
Let's say I wanted to pass in a String "howdy" and some object of type XYZ called XyzObj in. How would I specify that? WHat would I pass as params and what would I pass as args?
In Java this is called Reflection.
Assuming the class has this constructor, otherwise you will get a NoSuchMethod exception I believe.
clazz.asSubclass(asSubclassOfClass)
.getConstructor(String.class,XYZ.class)
.newInstance("howdy",XyzObj);
Since you are new to Java, let me give you an easier so that you can understand what's going on under the hood when you do this.
Assume you have the following class:
public class ParentClazz{
String someVar;
public ParentClazz(){
someVar="test";
}
public ParentClazz(String someVar){
System.out.println("I have been invoked");
this.someVar=someVar;
}
}
Then you have the following main method:
public static void main(String[] args) throws ParseException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
ParentClazz.class.asSubclass(ParentClazz.class).getConstructor(String.class).newInstance("howdy");
}
If you run this you will notice the console output print message - I have been invoked. This means that using reflection you have invoked the constructor of ParentClazz.
You can do the same thing if the scenario allows you is by using standard object creation process:
ParentClazz clazz = new ParentClazz("howdy");
Hope this helps you understand it.
Here is an example of creating classes without the new keyword.
The classes take other classes both primitives and Objects as their parameters.
The example also shows the instance of a subclass and a Parent class being created
public class ConstructorInstantiateWithoutNew
{
#SuppressWarnings("rawtypes")
public static void main( String [] args )
{
Class<Drinker> clazz_drinker = Drinker.class;
Class [] paramTypes = { Fizz.class, Colour.class, int.class };
Object [] paramValues = { new Fizz(), new Colour(), new Integer(10) };
Class<Drunk> clazz_drunk = Drunk.class;
Class [] paramTypesSub = { Fizz.class, Colour.class, int.class, boolean.class };
Object [] paramValuesSub = { new Fizz(), new Colour(), new Integer(10), true };
try
{
Drinker drinker = clazz_drinker.getConstructor( paramTypes ).newInstance( paramValues );
drinker.drink();
Drunk drunk = clazz_drunk.getConstructor(paramTypesSub).newInstance(paramValuesSub);
drunk.drink();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class Drinker
{
int n;
public Drinker( Fizz f, Colour c, int n)
{
this.n = n;
}
public void drink()
{
System.out.println( "Dad drank " + (n*10) + " ml");
}
}
class Drunk extends Drinker
{
boolean trouble;
public Drunk(Fizz f, Colour c, int n, boolean inDogHouse)
{
super(f,c,n);
trouble = inDogHouse;
}
public void drink()
{
System.out.println(
"Dad is Grounded: " + trouble +
" as he drank over "+
(n*10) + " ml");
}
}
class Fizz {} class Colour {}
Hope this is useful
Kind regards
Naresh Maharaj
clazz.asSubclass(asSubclassOfClass)
.getConstructor(String.class, XYZ.class)
.newInstance("howdy", XyzObj)
Which assumes that the constructor args are in the specified order