Related
What actually happens in a generic class when we compile the file and what happens at runtime? how does T behave at compile time vs runtime? What was the main purpose of introducing generics? Since we can do the same thing with the Object class. I am very much confused and have spent 3 months understanding this generic topic. Kindly anyone here, explain it in every detail. Thanks
//demo class, basically what is happening here ?
class Generic<T>{
Generic(){
T[] arr = (T[]) new Object[5];
}
public static void main(String [] args) {
new Generic();
}
} // class
// another demo class , let say i have a Student class
class AnotherGeneric<T extends Student> {
T fun(){
T data = (T)new Object();
return data;
}
public static void main(String[] args) {
Student std = new AnotherGeneric<Student>().fun();
}
}// class
Mostly, generics just disappear entirely at runtime. Generics is, in essence, "compiler checked documentation". It's a way to get both of these things at the same time:
You have a method that returns, say, a List. You'd like to document that the list only contains strings.
You'd like for the compiler to be aware of this and tell users who treat that list as if it contains something other than strings to go: "Hey, there - hang on. I don't think you understand how this method works, given that you appear to be treating it as if it has non-strings in it, which it won't, as the documentation says that it won't". Or vice versa: "Hey there - hang on. You documented that the list you return only contain strings but you appear to be attempting to stuff a number in there. That doesn't make sense. I shall not compile this inconsistency until you fix it".
And very much in last place, generics makes your code very slightly shorter, as the compiler will inserts casts for you silently. When the method is documented to return only a list of strings, when you call that method and then call .get(0) on the result, the compiler "pre-casts" it to a String for you.
That's it. It doesn't change anything at runtime. Those casts are even generated by the compiler.
So, how does it work:
In signatures, generics is compiled into the class file, but the JVM treats these as effectively 'a comment' - the JVM completely ignores them. The point of this is solely for the benefit of javac, who can read these comments and act accordingly. In other words, the fact that ArrayList has generics needs to be known by javac in order to properly compile the line new ArrayList<String>() - and how does javac know? By checking the class file that contains the ArrayList code. Signatures are:
The name of a class.
The extends and implements clauses of a class.
The type of every field, and the name of every field.
The return type of every method, and the name of every method.
The type (not name) of every parameter of a method.
The throws clause of a method.
Everywhere else, generics just disappear. So, if you write inside a method: List<String> list = new ArrayList<String>();, the code you end up with is JUST new ArrayList() in the class file. That string is just gone. It also explains why given a List<?> x; there is simply no way to ask this list: What is your component type. Because it is no longer available at runtime.
Javac uses this information to figure out what to do.
For the purposes of compilation, ALL generics-typed stuff is compiled as if they are their lower bound.
What about generic casts?
The closest other java language feature to a generic cast is #SuppressWarnings. A generic cast does literally nothing. It's just you telling the compiler: Shut up, I know what I'm doing (hence, you best really know what you are doing to use them!!).
For example, given:
void foo(List<?> x) {
List<String> y = (List<String>) x;
}
The compiler does nothing. There is no way for the compiler to generate code that actually checks if x really is a List. The above code cannot throw an exception, even if there are non-strings in that list. As I said before, generics also cause the compiler to inject casts. So, if you later write:
x.get(0).toLowerCase();
That will compile (there is no need to cast x.get(0) to String, however, it is compiled that way!) - and if you pass a list to this method that has a non-string object as first item, that line throws a ClassCastException even though you didn't write any casts on that line. That's because the compiler inserted a cast for you.
Think about it like this: Generics are for linking types in signatures.
Imagine you want to write a method that logs its argument and then just returns it. That's all it does.
You want to now 'link' the type of the argument to the return type: You want to tell the compiler and all users of this method: Whatever type you feed into this method is identical to the type that rolls of it.
In normal java you cannot do this:
Object log(Object o) {
log.mark("Logged: {}", o);
return o;
}
The above works fine but is annoying to use. I can't do this:
String y = scanner.next();
new URL(log(y)).openConnection();
The reason I can't do that, is the log(y) expression is of type Object, and the URL constructor requires a String. Us humans can clearly see that log(y) is obviously going to return a string, but the signature of the log method doesn't indicate this at all. We have to look at the implementation of log to know this, and perhaps tomorrow this implementation changes. The log method does not indicate that any future updates will continue to just 'return the parameter' like this. So javac does not let you write this code.
But now we add generics:
public <T> T log(T o) {
log.mark("Logged: {}", o);
return o;
}
And now it works fine. We've told the compiler that there exists a link between the 2 places we used T in this code: The caller gets to choose what T ends up being, and the compiler ensures that no matter what the caller chose, your code works.
Hence, if you define a type parameter and use it exactly 0 or 1 times, it's virtually always either a bug or a weird hack. The point is to link things and '0 or 1 times' is obviously not linking things.
Generics goes much further than this, your question's scope is far too broad. If you want to know every detail, read the Java Lang Spec, which gets into hopeless amounts of detail that will take your 6 months to even understand. There's no real point to this. You don't need to know the chemical composition of brake fluid to drive a car either.
This is the way I was taught the importance of generics.
Imagine that you were blindfolded, then told to do some basic task, such as move boxes from one side of the room to the other. Now also imagine that the room is full of other blindfolded people doing exactly the same thing as you.
Programming without generics would be tell all of these people to do their tasks, and then run the risk of them accidentally crashing into each other and damaging the boxes.
Programming with generics would be to sit down with each blindfolded person, and give all of them a very specific plan beforehand. For example, tell one of them to go forward 10 feet, grab the box on the floor in front of them, turn 180 degress, then go 10 feet, then put the box down. Then (and this is the important part) you draw a map of all of the plans and make sure that each of the blindfolded people's paths CANNOT cross each other. That is what generics give you. If you can prove that none of paths cross each other, then it doesn't matter if they are blindfolded - they cannot bump into each other - by design!
Once you can prove that they cannot bump into each other, you can start doing something more complex, like telling one blindfolded person to hand a box to another blindfolded person. And if you get really good at it, you can have paths that actually do cross, but only one person is crossing the intersection at the time.
That is the power of generics in Java - you can perform unsafe actions safely by planning it all ahead of time - at compile time! Then, when you are at runtime, it doesn't matter that you are blind - you know exactly what to do, and you have proven that you cannot crash into anyone else. As a result, when you actually do the task, you don't slowly shuffle forwards, putting your hands in front of you, constantly checking in fear that you will bump into someone else. You sprint headfirst forwards, blindly, but confident that you cannot fail, because the entire path has been mapped out for you.
Now, I should mention, the only way Java generics work is by ensuring none of the paths cross. You do this by turning on warnings when you compile your java code. If you get warnings about unchecked or raw, then that means your code is not safe, and you need to fix your plan. Once you compile with no warnings related to generics, you can be certain that your types are safe and will not crash into each other unexpectedly.
And finally, generics are powerful, but they do not play well with nulls. If you let nulls sneak into your code, that is a blindspot which generics cannot protect you from. Be very certain to limit, if not remove, the nulls in your code, otherwise your generics may not be bulletproof. If you avoid nulls and compile without warnings, you can guarantee that your code will never run into a type error unexpectedly.
Im trying to implement validation module used for handling events. The validation module is based on simple interface:
public interface Validator {
Optional<ValidationException> validate(Event event);
}
Existing code base in my team relies on the wrapping exception mechanism - I cannot really play with it.
I have encountered problems when implementing new validator, that is responsible for validating single event, in two terms.
Assume the event is PlayWithDogEvent, and it contains Toys a dog can play with.
Flow of validation of such event:
For each toy,
Check if its a ball
If its a ball, it should be not too large.
If any of the toys is either not a ball/too big ball, my validate(Event event) method should return Optional.of(new ValidationException("some msg")).
I have implemented my validator the following way:
public class ValidBallsOnlyValidator implements Validator {
#Override
public Optional<ValidationException> validate(Event event) {
try {
event.getToys().forEach(this::validateSingleToy);
return Optional.empty();
} catch (InvalidToyException ex) {
return Optional.of(new ValidationException(ex.getMessage()));
}
}
private void validateSingleToy(Toy toy) {
// In real code the optional here is kinda mandatory
Optional<Toy> potentialBall = castToyToBall(toy);
// Im using Java 8
if(potentiallBall.isPresent()) {
checkIfBallIsOfValidSize(potentialBall.get(), "exampleSize");
} else {
throw new InvalidToyException("The toy is not a ball!")
}
}
private void checkIfBallIsOfValidSize(Toy toy, String size) {
if(toyTooLarge(toy, size)) throw new InvalidToyException("The ball is too big!")
}
}
The piece seems to work just fine, but im uncomfortable with the way it looks. My biggest concern is whether it is a good practice to place whole stream processing inside single try. Moreover, I don't think such mixing of exception-catching + returning optionals is elegant.
I could use some advice and/or best practices for such scenarios.
but im uncomfortable with the way it looks.
The API you're working against is crazy design. The approach to dealing with silly APIs is generally the same:
Try to fix it 'upstream': Make a pull request, talk to the team that made it, etc.
If and only if that option has been exhausted, then [A] write whatever ugly hackery you have to, to make it work, [B] restrict the ugliness to as small a snippet of code as you can; this may involve writing a wrapper that 'contains' the ugly, and finally [C] do not worry about code elegance within the restricted 'ugly is okay here' area.
The reason the API is bizarre is that it is both getting validation wrong, and not capitalizing on the benefits of their mistake (as in, if I'm wrong about their approach being wrong, then at least they aren't doing the best job at their approach).
Specifically, an exception is a return value, in the sense that it is a way to return from a method. Why isn't that interface:
public interface Validator {
void validate(Event event) throws ValidationException;
}
More generally, validation is not a 'there is at most one thing wrong' situation, and that goes towards your problem with 'it feels weird to write a try/catch around the whole thing'.
Multiple things can be wrong. There could be 5 toys, one of which is a ball but too large, and one of which is a squeaky toy. It is weird to report only one error (and presumably, an arbitrarily chosen one).
If you're going to go with the route of not throwing validation exceptions but returning validation issues, then the issues should presumably not be exceptions in the first place, but some other object, and, you should be working with a List<ValidationIssue> and not with an Optional<ValidationIssue>. You've gotten rid of an optional, which is always a win, and you now can handle multiple issues in one go. If the 'end point' that processes all this is fundamentally incapable of dealing with more than one problem at the time, that's okay: They can just treat that list as an effective optional, with list.isEmpty() serving as the 'all is well' indicator, and list.get(0) otherwise used to get the first problem (that being the only problem this one-error-at-a-time system can deal with).
This goes to code elegance, the only meaningful way to define that word 'elegance': It's code that is easier to test, easier to understand, and more flexible. It's more flexible: If later on the endpoint code that deals with validation errors is updated to be capable of dealing with more than one, you can now do that without touching the code that makes validation issue objects.
Thus, rewrite it all. Either:
Make the API design such that the point is to THROW that exception, not to shove it into an optional, -or-
Make the API list-based, also get rid of optional (yay!) and probably don't work with a validation issue object that extends SomeException. If you're not gonna throw it, don't make it a throwable.
If that's not okay, mostly just don't worry about elegance so much - elegance is off the table once you're forced to work with badly designed APIs.
However, there's of course almost always some style notes to provide for any code.
return Optional.of(new ValidationException(ex.getMessage()));
Ordinarily, this is extremely bad exception handling and your linter tool SHOULD be flagging this down as unacceptable. If wrapping exceptions, you want the cause to remain to preserve both the stack trace and any exception-type-specific information. You're getting rid of all that by ignoring everything about ex, except for its message. Ordinarily, this should be new ValidationException("Some string that adds appropriate context", ex) - thus preserving the chain. If there is no context to add / it is hard to imagine what this might be, then you shouldn't be wrapping at all, and instead throwing the original exception onwards.
However, given that exceptions are being abused here, perhaps this code is okay - this again goes to the central point: Once you're committed to working with a badly designed API, rules of thumb on proper code style go right out the window.
private void checkIfBallIsOfValidSize(Toy toy, String size) {
if(toyTooLarge(toy, size)) throw new InvalidToyException("The ball is too big!")
}
Yes, this is a good idea - whilst the API expects you not to throw exceptions but to wrap them in optionals, that part is bad, and you should usually not perpetuate a mistake even if that means your code starts differing in style.
event.getToys().forEach(this::validateSingleToy);
Generally speaking, using the forEach method directly, or .stream().forEach(), is a code smell. forEach should be used in only two cases:
It's the terminal on a bunch of stream ops (.stream().filter().flatMap().map()....forEach - that'd be fine).
You already have a Consumer<T> object and want it to run for each element in a list.
You have neither. This code is best written as:
for (var toy : event.getToys()) validateSingleToy(toy);
Lambdas have 3 downsides (which turn into upsides if using lambdas as they were fully intended, namely as code that may run in some different context):
Not control flow transparent.
Not mutable local var transparent.
Not checked exception type transparent.
3 things you lose, and you gain nothing in return. When there are 2 equally succint and clear ways to do the same thing, but one of the two is applicable in a strict superset of scenarios, always write it in the superset style, because code consistency is a worthwhile goal, and that leads to more consistency (it's worthwhile in that it reduces style friction and lowers learning curves).
That rule applies here.
Returning exceptions instead of returning them is weird, but whatever. (Why not return a ValidationResult object instead? Exceptions are usually intended to be thrown and caught).
But you could change your private methods to also return Optional instances which would make it easier to combine them. It would also avoid mixing throwing and returning and streams. Not sure if that is what you are looking for?
public class ValidBallsOnlyValidator implements Validator {
#Override
public Optional<ValidationException> validate(Event event)
return event.getToys()
.stream()
.filter(Optional::isPresent)
.findFirst()
.map(ex -> new ValidationException(ex.getMessage()));
}
private Optional<InvalidToyException> validateSingleToy(Toy toy) {
// In real code the optional here is kinda mandatory
Optional<Toy> potentialBall = castToyToBall(toy);
if(potentiallBall.isPresent()) {
return checkIfBallIsOfValidSize(potentialBall.get(), "exampleSize");
} else {
return Optional.of(new InvalidToyException("The toy is not a ball!"));
}
}
private Optional<InvalidToyException> checkIfBallIsOfValidSize(Toy toy, String size) {
if(toyTooLarge(toy, size)) return Optional.of(new InvalidToyException("The ball is too big!"));
return Optional.empty();
}
}
In my understanding, code testing is to test whether results are right, like a calculator, I need to write a test case to verify if the result of 1+1 is 2.
But I have read many test cases about verifying the number of times a method is called. I'm very confused about that. The best example is what I just saw in Spring in Action:
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnightTest {
#Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
BraveKnight knight = new BraveKnight(mockQuest);
knight.embarkOnQuest();
verify(mockQuest, times(1)).embark();
}
}
I really have no idea about why they need to verify the embark() function is called one time. Don't you think that embark() will certainly be invoked after embarkOnQuest() is called? Or some errors will occur, and I will notice error messages in the logs, which show the error line number, that can help me quickly locate the wrong code.
So what's the point of verifying like above?
The need is simple: to verify that the correct number of invocations were made. There are scenarios in which method calls should not happen, and others in which they should happen more or less than the default.
Consider the following modified version of embarkOnQuest:
public void embarkOnQuest() {
quest.embark();
quest.embarkAgain();
}
And suppose you are testing error cases for quest.embark():
#Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
Mockito.doThrow(RuntimeException.class).when(mockQuest).embark();
...
}
In this case you want to make sure that quest.embarkAgain is NOT invoked (or is invoked 0 times):
verify(mockQuest, times(0)).embarkAgain(); //or verifyZeroInteractions
Of course this is one other simple example. There are many other examples that could be added:
A database connector that should cache entries on first fetch, one can make multiple calls and verify that the connection to the database was called just once (per test query)
A singleton object that does initialization on load (or lazily), one can test that initialization-related calls are made just once.
Consider the following code:
public void saveFooIfFlagTrue(Foo foo, boolean flag) {
if (flag) {
fooRepository.save(foo);
}
}
If you don't check the number of times that fooRepository.save() is invoked , then how can you know whether this method is doing what you want it to?
This applies to other void methods. If there is no return to a method, and therefore no response to validate, checking which other methods are called is a good way of validating that the method is behaving correctly.
Good question. You raise a good point that mocking can be overly circuitous when you can just check the results. However, there are contexts where this does lead to more robust tests.
For example, if a method needs to make a call to an external API, there are several problems with simply testing the result:
Network I/O is slow. If you have many checks like this, it will slow down your test case
Any round-trip like this would have to rely on the code making the request, the API, and the code interpreting the API's response all to work correctly. This is a lot of failure points for a single test.
If something stupid happens and you accidentally make multiple requests, this could cause performance issues with your program.
To address your sub-questions:
Don't you think that embark() will certainly be invoked after embarkOnQuest() called?
Tests also have value in letting you refactor without worry about breaking things. This is obvious now, yes. Will it be obvious in 6 months?
I really have no idea about why they need to verify the embark()
function is called one time
Verifying an invocation on a mock for a specific number of times is the standard way how Mockito works as you invoke Mockito.verify().
In fact this :
verify(mockQuest, times(1)).embark();
is just a verbose way to write :
verify(mockQuest).embark();
In a general way, the verification for a single call on the mock is what you need.
In some uncommon scenarios you may want to verify that a method was invoked a specific number of times (more than one).
But you want to avoid using so specific verifications.
In fact you even want to use verifying as few as possible.
If you need to use verifying and besides the number of invocation on the mock, it generally means two things : the mocked dependency is too much coupled to the class under
test and or the method under test performs too many unitary tasks that produce only side effects.
The test is so not necessary straight readable and maintainable. It is like if you coded the mock flow in the verifying invocations.
And as a consequence it also makes the tests more brittle as it checks invocation details not the overall logic and states.
In most of cases, a refactoring is the remedy and cancel the requirement to specify a number of invocation.
I don't tell that it is never required but use it only as it happens to be the single decent choice for the class under test.
I ran into an odd situation during a use case on a project: ESQL is calling a java method, sending it a String input parameter which the method will unmarshal, apply some logic, and then store useful info from the unmarshalled object. So, the method must either throw a JAXBException, or use a try catch in order to handle the possible exceptions.
The problem with this is, that ESQL cannot invoke a java method which includes a throws in the signature. BUT, we want any errors to fall through back to the previously calling MBNode so it can be handled appropriately there, so then trycatch is out of the picture.
It struck me that hey, is it not possible to return a type of Exception when we encounter an issue, and null if not? So I wrote a simple method doing so, and though I didn't get any warnings or errors, it seemed just wrong to me in the sense of good programming.
For example:
public Exception doStuffAndCheckForErorrs(String inString)
{
if(inString.equals(null))
{
return new Exception("Your string is null");
}
else
return null;
}
But I just get a terrible feeling about doing anything this way.
I'm open to any thoughts or different solutions to this, especially if there's a way around the ESQL signature issue.
UPDATE:
Adding reference as to why the ESQL procedure cannot call a java method with a throws clause in the signature.
Excerpt from This link under the CREATE PROCEDURE statement section:
"Any Java method that you want to invoke must have the following basic signature:
public static (< 0 - N parameters>)
where must be in the list of Java IN data types in the table in ESQL to Java data type mapping (excluding the REFERENCE type, which is not permitted as a return value), or the Java void data type. The parameter data types must also be in the ESQL to Java data type mapping table. In addition, the Java method is not allowed to have an exception throws clause in its signature."
This isn't really a question about Java, it's a question about ESQL.
ESQL is able to cope with Java exceptions being thrown through the JNI into ESQL code, you should get a BIP2917 error.
I initially though this might have been an issue with the ESQL method resolver but on IIB v9 I was able to succesfully call the following method:
public static void sayHello() throws Exception{
System.out.println("hello");
}
This makes me think that perhaps you got something else wrong with your ESQL external function/procedure definition?
The point here is you can't DECLARE an exception will be thrown; you can still throw a RuntimeException - without adding a throws clause.
So if you wrap your JAXBException into a RuntimeException, you can throw it and handle according to your requirements, without breaking either requirement. Not sure if I would do that; I would not like to return an exception-type though as it's not meant to be used as a return code.
Be extra sure that this asynch way of handling the issue won't break the ESQL library, as you'll be bypassing part of their code, possibly leaving part of it hanging.
Returning Exception is "quick and dirty". It can be very powerful and useful but this should be avoid if possible.
The invocation in ESQL are made like this for a good reason i won't explained here but you can bypass it by using RuntimeException that does not appears in the method definition.
A use case that specifies throwing an Exception sounds like it may be poorly written.
What is the business or architectural reason for throwing an Exception?
An alternative would be throw a RuntimeException or a custom subclass.
That would allow you to leave it out of the method signature.
Again, the use case seems odd.
The straightforward answer to your question is:
No, it isn't good programming to have a return type of Exception.
The mechanism is meant to happen when something goes wrong, therefore a return type of Exception means that you want to receive the consequence of something that went wrong.
I understand that you can't throw Exception, so you should handle the case with other approach.
The boolean aproach is fine when you want to check up some work: good = return true, bad= return false.
The encapsulation of values in an Object is meant when you want to grab the results of the work: good = return new YourResultObject(val1, val2, ..., valx), bad = return null.
What you can do is use return codes like C programs used to do to report about their states.
Alternatively you can also create an Enum and return the Enum, both are more flexible than the Boolean approach if you want to differentiate between different types of errors
public Enum ReturnCodes {
SUCCESS,
NULLSTRING,
...,
OTHERERROR,
}
I have a deceptively simple scenario, and I want a simple solution, but it's not obvious which is "most correct" or "most Java".
Let's say I have a small authenticate(Client client) method in some class. The authentication could fail for a number of reasons, and I want to return a simple boolean for control flow, but also return a String message for the user. These are the possibilities I can think of:
Return a boolean, and pass in a StringBuilder to collect the message. This is the closest to a C-style way of doing it.
Throw an exception instead of returning false, and include the message. I don't like this since failure is not exceptional.
Create a new class called AuthenticationStatus with the boolean and the String. This seems like overkill for one small method.
Store the message in a member variable. This would introduce a potential race condition, and I don't like that it implies some state that isn't really there.
Any other suggestions?
Edit Missed this option off
Return null for success - Is this unsafe?
Edit Solution:
I went for the most OO solution and created a small AuthenticationResult class. I wouldn't do this in any other language, but I like it in Java. I also liked the suggestion
of returning an String[] since it's like the null return but safer. One advantage of the Result class is that you can have a success message with further details if required.
Returning a small object with both the boolean flag and the String inside is probably the most OO-like way of doing it, although I agree that it seems overkill for a simple case like this.
Another alternative is to always return a String, and have null (or an empty String - you choose which) indicate success. As long as the return values are clearly explained in the javadocs there shouldn't be any confusion.
You could use exceptions....
try {
AuthenticateMethod();
} catch (AuthenticateError ae) {
// Display ae.getMessage() to user..
System.out.println(ae.getMessage());
//ae.printStackTrace();
}
and then if an error occurs in your AuthenticateMethod you send a new AuthenticateError (extends Exception)
Avoid returning a "sentinel value", especially null. You will end up with a codebase where methods cannot be understood by the caller without reading the implementation. In the case of null, callers may end up with NullPointerExceptions if they forget (or don't know) that your method may return null.
The tuple suggestion from Bas Leijdekkers is a good one that I use all the time if I want to return more than one value from a method. The one we use is P2<A, B> from the Functional Java library. This kind of type is a joint union of two other types (it contains one value of each type).
Throwing Exceptions for control flow is a bit of a code smell, but checked exceptions are one way of getting more than one type of value from a method. Other, cleaner possibilities exist though.
You can have an Option<T> abstract class with two subclasses Some<T> and None<T>. This is a bit like a type-safe alternative to null, and a good way to implement partial functions (functions whose return value isn't defined for some arguments). The Functional Java library has a full-featured Option class that implements Iterable<T>, so you can do something like this:
public Option<String> authenticate(String arg) {
if (success(arg))
return Option.some("Just an example");
else
return Option.none();
}
...
for(String s : authenticate(secret)) {
privilegedMethod();
}
Alternatively, you can use a disjoint union of two types, as an Either<L, R> class. It contains one value which is either of type L or R. This class implements Iterable<T> for both L and R, so you can do something like this:
public Either<Fail, String> authenticate(String arg) {
if (success(arg))
return Either.right("Just an example");
else
return Either.left(Fail.authenticationFailure());
}
...
Either<Fail, String> auth = authenticate(secret);
for(String s : auth.rightProjection()) {
privilegedMethod();
}
for(Fail f : auth.leftProjection()) {
System.out.println("FAIL");
}
All of these classes, P2, Option, and Either are useful in a wide variety of situations.
Some more options:
Return an separate enum value for each type of failure. The enum object could contain the message
Return an int and have a separate method that looks up the appropriate message from an array
create a generic utility tuple class that can contains two values. Such a class can be useful in many more places.
simple tuple example, actual implementation may need more:
class Tuple<L, R> {
public final L left;
public final R right;
public Tuple( L left, R right) {
this.left = left;
this.right = right;
}
}
You could return a Collection of error messages, empty indicating that there were no problems. This is a refinement of your third suggestion.
I personally think creating a new class called AuthenticationStatus with the boolean and the String is the most Java like way. And while it seems like overkill (which it may well be) it seems cleaner to me and easier to understand.
Just because failed authentication is commonplace doesn't mean it isn't exceptional.
In my opinion, authentication failures are the poster-child use case for checked exceptions. (Well... maybe file non-existence is the canonical use case, but authentication failure is a close #2.)
I use the "tiny class" myself, usually with an inner class. I don't like using arguments to collect messages.
Also, if the method that might fail is "low level" - like coming from an app server or the database layer, I'd prefer to return an Enum with the return status, and then translate that into a string at the GUI level. Don't pass around user strings at the low level if you're ever going to internationalize your code, because then your app server can only respond in one language at a time, rather than having different clients working in different languages.
Is this the only method where you have such a requirement? If not, just generate a general Response class with an isSuccessful flag and a message string, and use that everywhere.
Or you could just have the method return null to show success (not pretty, and does not allow returning a success AND a message).
I would most probably go for something like :
class SomeClass {
public int authenticate (Client client) {
//returns 0 if success otherwise one value per possible failure
}
public String getAuthenticationResultMessage (int authenticateResult) {}
//returns message associated to authenticateResult
}
With this "design", you can ask for a message only when authentication fails (which I hope is the scenario that occurs 99,99% of time ;))
It may also be of good practice to delegate message resolution to another Class. But it depends of your application needs (mostly, does it need i18n ?)
This seems like a common idiom in other programming languages, but I cannot figure out which one ( C I guess as I read in the question ) .
Almost the same question is posted here and here
Attempting to return two values from a single function, may be misleading. But as it has been proved by the attempts of doing so, it may be very useful too.
Definitely creating and small class with the results should be the correct way to proceed if that is a common flow in the app as posted before.
Here's a quote about returning two values from a function:
As a matter of programming style, this idea is not
appealing in a object oriented programming language.
Returning objects to represent computation results
is the idiom for returning multiple values. Some
suggest that you should not have to declare classes
for unrelated values, but neither should unrelated
values be returned from a single method.
I've found it in a feature request for java to allow multiple return values
look at the "evaluation" section dated: 2005-05-06 09:40:08
Successful authentication should be the "normal" case, so an authentication failure is the exceptional case.
What are the different status strings for the user anyway. I can see only two, success or failure. Any further information is a potential security issue.
Another advantage of the solution with exceptions is that it cannot be called in the wrong way and the failure case is more obvious. Without exceptions, you write:
if (authenticate()) {
// normal behaviour...
}
else {
// error case...
}
You can accidently call the method ignoring the return value. The "normal behaviour" code is then executed without successful authentication:
authenticate();
// normal behaviour...
If you use exceptions, that cannot happen. If you decide to not use exceptions, at least name the method so that it is clear that it returns a state, e. g.:
if (isAuthenticated()) {
//...
}
There are a lot of good answers here so I will keep it short.
I think failure of a user to authenticate can be considered a valid case for a checked exception. If your style of programming favoured handling exceptions then there would be no reason not to do this. It also removes the "How to return multiple values from a method, my method does one thing It authenticates a user"
If you are going to return multiple values then spend 10 minutes creating a generic PairTuple (can also be more than a pair TripleTuple, I won't repeat the example listed above) and return your values that way.
I hate having small dto style objects to return various multiple values they just clutter the place.
How about returning a string. Empty or Null for success. Error Message in case of failure.
Simplest that would work. However not sure if it reads well.
Return the Object. It allows you to put additional functionality into the Class if you need it. Short lived objects in Java are quick to create and collect.
I would choose the Exception option in first place.
But, in second place, I would prefer the C-style technique:
public boolean authenticate(Client client, final StringBuilder sb) {
if (sb == null)
throw new IllegalArgumentException();
if (isOK()) {
sb.append("info message");
return true;
} else {
sb.append("error message");
return false;
}
}
This is not so strange and it's done in many places in the framework.
Instead of creating a special object for return type, I usually just return an array where all the returned information is stored. The benefit is that you can extend this array with new elements without creating new types and mess. The downside you have to know exactly what elements should present when array is returned from particular method to parse it correctly. Usually I agree on certain structure, like first element is always Boolean indication success, second is String with description, the rest is optional.
Example:
public static void main(String[] args)
{
Object[] result = methodReturningStatus();
if(!(Boolean)result[0])
System.out.println("Method return: "+ result[1]);
}
static Object[] methodReturningStatus()
{
Object[] result = new Object[2];
result[0] = false;
result[1] = "Error happened";
return result;
}