Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Prochaines sessions inter-entreprises : 28-31 mars 2017 / 13-16 juin 2017
Sessions intra-entreprises sur demande.
Inscrivez-vous vite !

Java Quiz in Unicorn land

Some days ago, ZeroTurnaround, of JRebel fame, published a funny Java Quiz on their website.
It is not very hard, and there are at least 3 different solutions that I know of.

Below is my solution ; but try to find your own before taking a look !

My solution :

The whole goal of this quiz is to find a way to identify and differenciate the contexts in which the two messages are used, to avoid printing any of them multiple times.
One major difficulty is that the Unicorn.pat() method is called a random number of times for each message, so we cannot rely on some counter to allow patting or not.

But one thing we do know, is that our Unicord.pat() method is called at two different lines in MagicalLand, each one being responsible of the printing of a particular message. If we manage to allow only one patting per call site, we should be good.
And it is fairly easy to know where you are called from : just look at the call stack !

The implementation is straightforward : create an Exception to get a stack trace, find the calling line, and ensure we don't allow patting more than once per call site.

public class Unicorn {
 
    static int line;
 
    public static boolean pat() {
        int thisLine = new Exception().getStackTrace()[1].getLineNumber();
        boolean shouldPat = line==0 || thisLine!=line;
        line = thisLine;
        return shouldPat;
    }
 
}

So, what is your solution ?


Commentaires

1. Le mercredi 20 février 2013, 16:04 par Alexandre

I did it using Thread.currentThread() instead of throwing a new Exception, and using a Set, taking advantage of its add method which returns true if the set was modified to shorten the code a little.

The gist is here: https://gist.github.com/agrison/499...

2. Le mercredi 20 février 2013, 16:12 par Olivier Croisier

Huh, I was not aware that one could read the stack through the Thread class, this is interesting.

3. Le mercredi 20 février 2013, 16:28 par Alexandre

@Olivier That way and yours are the only one I know of (or I can remember of).
I imagine it may be possible to do it using aspects, retrieving the caller from the join point (it would be fun to see).

However, I would be interested in the two other ways you said knowing in your post :-).

4. Le mercredi 20 février 2013, 16:46 par Piwaï

Well, if you look at Thread.getStackTrace() here: http://grepcode.com/file_/repositor...

You'll notice this:
return (new Exception()).getStackTrace();

5. Le mercredi 20 février 2013, 17:30 par Jo

Are we allowed to implement a 3rd class ?

6. Le jeudi 21 février 2013, 04:59 par Damien

Here is a different solution:
https://gist.github.com/damienlepag...

7. Le vendredi 22 février 2013, 15:45 par HollyDays

Hi Olivier!

I hope you're been given the source of the MagicalLand class, or at least a MagicalLand.class file with debugging information.

Because if the quiz author only provides you with an already-compiled MagicalLand class with no debug info, then you're stuck!

As the javadoc says: StackTraceElement.getLineNumber() returns a negative number whatever the actual line if this line information is unavailable. And why would it be unavailable? Typically because no debug info was included while compiling the class!

8. Le vendredi 22 février 2013, 16:00 par Olivier Croisier

Unless you explicitely disable them at compile-time, some debug informations are automatically included in the binary class files - at least file name & line number, see the -g option on http://docs.oracle.com/javase/7/doc...

And no such limitation was specified by the quiz author :)

9. Le lundi 25 février 2013, 08:48 par jpvee

My solution is to have Unicorn.pat() always return true and instead replace the standard System.out with a custom implementation of PrintStream which overrides the println() method in a way that only allows each output once.

10. Le mardi 26 février 2013, 08:27 par error3

public class Math {

    public static double random() {
           return -1.0/500.0;
       }
}

public class Unicorn {

   public static boolean pat() {
       return true;
   }

}

11. Le mardi 26 février 2013, 10:53 par Jo

@error3 That was my first idea too.
That's also what i did to get maximum score on Olympic Games Google Doodle :)

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.