Over a million developers have joined DZone.

Java Code Challenge: Chemical Symbol Naming (Part 2) — Solution

It's time for part two the solution. See how Sam Atkinson coded his way through his challenge, and see how a few community members did it as well!

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

If you need a reminder of what's involved in the challenge, check out the article here.

This week's challenge was a nice, easy one, assuming you had completed part one of the challenge, as it was very much leveraging the same code.

The solution really depended on the extension piece for part one, which gave you a method to  find all valid symbols for an element. Let's look at the code solution from Drippel as an example:

for( String chemical : chemicals ){


 List<String> symbols = ChemicalNamer.generateAllSymbols(chemical);

    String toAdd = null;

    for( String symbol : symbols ){

    if( !allSymbols.contains(symbol)){
    toAdd = symbol;
    break;
    }
    }

    if( toAdd == null ){
    // we are done
    System.out.println("stopper:"+ chemical);
    break;
    }


All the logic for finding valid names is put into the static ChemicalNamer class. The possible solutions are looped over, and the first valid one is set. This code in particular is a great opportunity for a valid use of Java 8 functional code, and could be refactored like so:

Optional<String> element = 
  symbols.stream().filter(
  symbol -> !allSymbols.contains(symbol)
   ).findFirst();

if(!element.isPresent()){
System.out.println("stopper:"+ chemical);
break;
}


I'm generally not a fan of break clauses, so using the findFirst method is a nice way to remove this.

Looking Stylish

With the solution being relatively simple, I want to take this week as an opportunity to dive into a couple of areas of style and clean code pertinent to this challenge, starting off with data.

Getting Data in the System

Their solutions all tended to use file inputs; everyone tended to use BufferedReader to bring in the values from a text file, and I like that jaumemoral pulled this out into a different class with TextFileReader, allowing them to test the file-reading separately and generally just supporting good cohesion.

However, I personally went for a different approach. I've no plans to regularly be re-running this over different data sets, so I just coded the list into a "Data" class.

package com.samatkinson;

public class Data {
    public static String[] elements = new String[]{
        "Hydrogen",
        "Helium",
        "Lithium",
        "Beryllium",
        "Boron",
        "Carbon",
        "Nitrogen",
        "Oxygen",
        "Fluorine",
        "Neon",
        "Sodium",
        "Magnesium",
        "Aluminium",
        "Silicon",
        "Phosphorus",
        "Sulfur",
        "Chlorine",
        "Argon",
        "Potassium",
        "Calcium",
        "Scandium",
        "Titanium",
        "Vanadium",
        "Chromium",
        "Manganese",
        "Iron",
        "Cobalt",
        "Nickel",
        "Copper",
        "Zinc",
        "Gallium",
        "Germanium",
        "Arsenic",
        "Selenium",
        "Bromine",
        "Krypton",
        "Rubidium",
        "Strontium",
        "Yttrium",
        "Zirconium",
        "Niobium",
        "Molybdenum",
        "Technetium",
        "Ruthenium",
        "Rhodium",
        "Palladium",
        "Silver",
        "Cadmium",
        "Indium",
        "Tin",
        "Antimony",
        "Tellurium",
        "Iodine",
        "Xenon",
        "Caesium",
        "Barium",
        "Lanthanum",
        "Cerium",
        "Praseodymium",
        "Neodymium",
        "Promethium",
        "Samarium",
        "Europium",
        "Gadolinium",
        "Terbium",
        "Dysprosium",
        "Holmium",
        "Erbium",
        "Thulium",
        "Ytterbium",
        "Lutetium",
        "Hafnium",
        "Tantalum",
        "Tungsten",
        "Rhenium",
        "Osmium",
        "Iridium",
        "Platinum",
        "Gold",
        "Mercury",
        "Thallium",
        "Lead",
        "Bismuth",
        "Polonium",
        "Astatine",
        "Radon",
        "Francium",
        "Radium",
        "Actinium",
        "Thorium",
        "Protactinium",
        "Uranium",
        "Neptunium",
        "Plutonium",
        "Americium",
        "Curium",
        "Berkelium",
        "Californium",
        "Einsteinium",
        "Fermium",
        "Mendelevium",
        "Nobelium",
        "Lawrencium",
        "Rutherfordium",
        "Dubnium",
        "Seaborgium",
        "Bohrium",
        "Hassium",
        "Meitnerium",
        "Darmstadtium",
        "Roentgenium",
        "Copernicium",
        "Ununtrium",
        "Flerovium",
        "Livermorium",
        "Garfieldium",
        "Odium",
        "Nermalium",
        "Pookium",
        "Arbukelium",
        "Binkium",
        "Lizzium",
        "Arlenium",
        "Orsonium",
        "Royium",
        "Wadium",
        "Bookerium",
        "Sheldon",
        "Boium",
        "Lanoline",
        "Leonardium",
        "Donatellium",
        "Michelangelon",
        "Raphaellium",
        "Splinterium",
        "Oneilium",
        "Jonesium",
        "Shredderite",
        "Stockmanium",
        "Beboppium",
        "Rocksteadium",
        "Krangium",
        "Gruffium",
        "Zummium",
        "Grammium",
        "Tummium",
        "Sunnium",
        "Cubbium",
        "Guston",
        "Cavinium",
        "Callaum",
        "Gregorium",
        "Igthornium",
        "Scroogium",
        "Hueum",
        "Dewium",
        "Louium",
        "Webbium",
        "Beaklium",
        "Duckworthium",
        "Bubbium",
        "Tootsium",
        "Mcquackium",
        "Gearloosium",
        "Gizmodium",
        "Glomgoldium",
        "Beaglium",
        "Magica",
        "Drakium",
        "Gosalon",
        "Muddlefootium",
        "Morganium",
        "Hooterium",
        "Gryzlikoffium",
        "Negaduckium",
        "Bushrootium",
        "Megavoltium",
        "Jagaium",
        "Lionoium",
        "Tygram",
        "Panthron",
        "Cheetaram",
        "Snarfium",
        "Jemium",
        "Kimberium",
        "Ajaleithum",
        "Shanium",
        "Carmenium",
        "Pizzazzium",
        "Roxium",
        "Stormerium",
        "Jettium",
        "Riotium",
        "Rapturium",
        "Minxium",
        "Chippium",
        "Dalium",
        "Monterium",
        "Hackwrenchium",
        "Zipperium",
        "Fatcatium",
        "Nimnulum",
        "Tommium",
        "Chuckium",
        "Phillium",
        "Lillium",
        "Angelicum",
        "Susium",
        "Dillium",
        "Kimium",
        "Stuium",
        "Didium",
        "Drewium",
        "Bettium",
        "Renium",
        "Stimpium",
        "Muddium",
        "Powderedtoastium",
        "Optimusprimium",
        "Bumblebium",
        "Cliffjumperium",
        "Wheeljackium",
        "Prowlium",
        "Megatronium",
        "Soundwavium",
        "Shockwavium",
        "Skywarpium",
        "Starscreamium",
        "Gadgetium",
        "Pennium",
        "Brainium",
        "Clawium",
        "Quimbium",
        "Alvinium",
        "Simonium",
        "Theodorium",
        "Davium",
        "Brittanium",
        "Jeanettium",
        "Eleanorium",
        "Prefectium",
        "Dentium",
        "Beeblebroxium",
        "Trilliane",
        "Marvinium",
        "Slartium",
        "Deepthoughtium",
        "Vogone",
        "Jeltzium",
        "Eddium",
        "Fenchurchium",
        "Halfruntium",
        "Majikthise",
        "Vroomfondelium",
        "Colluphidium",
        "Alfium",
        "Gordonium",
        "Willium",
        "Katium",
        "Luckium",
        "Homerium",
        "Margium",
        "Bartium",
        "Lisium",
        "Maggium",
        "Nedium",
        "Toddium",
        "Roddium",
        "Burnsium",
        "Smitheron",
        "Karlium",
        "Lennium",
        "Moeium",
        "Barnium",
        "Krustium",
        "Skinnerium",
        "Mcclurium",
        "Mcbanium",
        "Itchium",
        "Scratchium",
        "Wiggium",
        "Springfieldium",
        "Murdockium",
        "Baracium",
        "Hanniblium",
        "Facium",
        "Martium",
        "Brownium",
        "Biffium",
        "Lorrainium",
        "Georgium",
        "Stricklandium",
        "Goldium",
        "Claytonium",
        "Hillvallium",
        "Deloreum",
        "Waynium",
        "Garthium",
        "Benjamine",
        "Cassandrium",
        "Vanderhoffium",
        "Stacium",
        "Buttercupium",
        "Westlium",
        "Inigon",
        "Fezzikium",
        "Vizzinium",
        "Humperdinkum",
        "Rugenium",
        "Maxium",
        "Valerium",
        "Sarahium",
        "Jarethium",
        "Tobium",
        "Hogglium",
        "Didymusium",
        "Simbium",
        "Mufasium",
        "Scarium",
        "Nalium",
        "Timonium",
        "Pumbaaium",
        "Rafikium",
        "Zazuium",
        "Sarabium",
        "Shenzium",
        "Banzium",
        "Edium",
        "Bellium",
        "Beastium",
        "Cogsworthium",
        "Pottsium",
        "Lumierium",
        "Gastonium",
        "Lefouium",
        "Mauricium",
        "Woodium",
        "Buzzium",
        "Slinkium",
        "Rexium",
        "Hammium",
        "Andium",
        "Siddium",
        "Smithium",
        "Philium",
        "Vivianium",
        "Carltonium",
        "Hilarium",
        "Ashlium",
        "Geoffrium",
        "Sinclarium",
        "Earlium",
        "Franium",
        "Robbium",
        "Charlenium",
        "Babium",
        "Ethylium",
        "Hessium",
        "Richfieldium",
        "Littlefootium",
        "Ceraium",
        "Duckium",
        "Petrium",
        "Spikium",
        "Longneckium",
        "Sharptoothium",
    };
}


This way, I don't have to worry about the added complexity of file reading, and we're only dealing with a few hundred elements, which isn't much to be worrying about. In times past, there was a big preference to externalize everything (particularly as properties files) for that "just in case" moment when things need to be changed.  

While that can still be valid, as we move to a DevOps culture where we can get from commit to tests to deploy in under an hour, I encourage you to look at hard coding your values in where appropriate. This discourages making changes direct on the box, which creates snowflake servers and leaves you in a whole world of pain.

Static vs. Instance

I've been having this debate with people recently a lot and I've simply not come to a conclusion and would love to hear from you, the reader. 

Take for example the code we looked at before from Drippel:

ChemicalNamer.generateAllSymbols(chemical);

As a rule of thumb, I don't like static method calls. They aren't object oriented as they are pure functions without state. Particularly as this method is called repeatedly in the loop, I would probably move it to being an instance method and inject an instance of ChemicalNamer at the top, which then gives me control for mocking.

But what about when we have a genuine Util function, something that's used once, and has no state? If we made this OO, the code would be horrible, like so:

new TextUtils().randomStringStartingWith("x--")


If there is zero state in TextUtils then it should probably be static. But as I said, I think static methods are quintessentially un-object oriented.  I still haven't figured out what the right thing to do is and I continue to use static methods- have you got any thoughts?

Test Names

I'm pleased to see the solutions all came with tests, but naming clearly seems to be a problem.  Here are some of the test names from a variety of solutions; can you tell me what they do?


@Test
public void accept() 


@Test
public void register()


@Test
public void test_4() 


@Test
public void test_5() 


Make your test names descriptive! A good rule of thumb is that your test names should act as a readable requirements specification. You read the test names, you know what the class does. In the case of "accept()" above (taken from here)  I would rename it to "validatesChemicalSymbolIsValidForElement()". You now know what the functionality is that's expected from the implementation and that the test is designed to express it.

As always, any questions or let me know your thoughts in the comments. Some great solutions this week, well-done all!

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
clean code ,code challenge

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}