My goal is to use the periodic table of elements (or a list) to get information about a specific element in Java. I want to search it by atomic number and symbol (but that conversion should be simple).
I found that information in this JQuery plugin. But it is stored as a JSON file.
It seems like it would be most efficient to hardcode the information (since it doesn't change too often and due to performance reasons), but how do I convert JSON to a hardcoded enum
?
Since:
- the information about elements is totally static
- each elemental symbol is alphanumeric
- the discovery of new elements is both rare and irrelevant (because they are extremely unstable)
An enum seems a good option:
public enum Element {
H(1, "Hydrogen", 1.008, -259.1),
He(2, "Helium", 4.003, -272.2),
Li(3, "Lithium", 6.941, 180.5),
// ... 90+ others
;
private static class Holder {
static Map<Integer, Element> map = new HashMap<Integer, Element>();
}
private final int atomicNumber;
private final String fullName;
private final double atomicMass;
private final double meltingPoint;
private Element(int atomicNumber, String fullName, double atomicMass, double meltingPoint) {
this.atomicNumber = atomicNumber;
this.fullName = fullName;
this.atomicMass = atomicMass;
this.meltingPoint = meltingPoint;
Holder.map.put(atomicNumber, this);
}
public static Element forAtomicNumber(int atomicNumber) {
return Holder.map.get(atomicNumber);
}
public int getAtomicNumber() {
return atomicNumber;
}
public String getFullName() {
return fullName;
}
public double getAtomicMass() {
return atomicMass;
}
public double getMeltingPoint() {
return meltingPoint;
}
}
There's a bit of java kung fu going on here that deserves an explanation. The map is put inside a static inner (holder) class so it gets initialized before the enum instances are initialized, that way they can add themselves to it. If not in the inner static class, it would not be initialize, because the first thing initialized in the enum class must be the instances, but static inner classes are initialized before the class is initialized.
This approach means the the instances don't need to be listed in any particular order (they could be alphabetical listed, or otherwise).
Suppose you have a PeriodicTable.txt
file with following format:
ATOMIC_NUMBER SYMBOL OTHER_INFO
Like:
1 H Hydrogen -> Lightest element
2 He Helium -> Second lightest element
3 Li Lithium -> Third lightest element
// and so on...
Then you can have a fairly straightforward implementation of your own PeriodicTable
like following:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class PeriodicTable
{
private List<Element> elements;
public PeriodicTable() throws IOException
{
elements = new ArrayList<>();
List<String> list = Files.readAllLines(Paths.get("PeriodicTable.txt"));
list.forEach(this::process);
}
public static void main(String[] args) throws IOException
{
final PeriodicTable periodicTable = new PeriodicTable();
System.out.println(periodicTable.getElementByNumber(1));
System.out.println(periodicTable.getElementBySymbol("Li"));
}
private void process(String line)
{
try (Scanner scanner = new Scanner(line))
{
int atomicNumber = scanner.nextInt();
String symbol = scanner.next();
String info = scanner.nextLine();
elements.add(new Element(atomicNumber, symbol, info));
}
}
public Element getElementByNumber(int atomicNumber)
{
return elements.stream().
filter(e -> e.atomicNumber == atomicNumber).
findFirst().orElse(null);
}
public Element getElementBySymbol(String symbol)
{
return elements.stream().
filter(e -> e.symbol.equals(symbol)).
findFirst().orElse(null);
}
private class Element
{
private String info;
private int atomicNumber;
private String symbol;
public Element(int atomicNumber, String symbol, String info)
{
this.atomicNumber = atomicNumber;
this.symbol = symbol;
this.info = info;
}
public String toString()
{
return "[ " + atomicNumber + " " + symbol + " " + info + " ]";
}
}
}
If you see, I have created an Element
class which holds the atomic number
, symbol
, and info
of the element, and I have a list of elements
in PeriodicTable
class.
I read the PeriodicTable
data from the PeriodicTable.txt
file and process each line of the text file by parsing it appropriately and creating element for each line and adding it to the elements
.
I also add two methods for filtering the element based on atomic number
and symbol
properties.
The code works in Java 8, so you should have at least that to run it, or one can easily write a code for this which will run on earlier JVMs, though it won't be as compact as this one.
Since there are just limited number of elements in the PeriodicTable, I don't bother to have elements sorted by their atomic number
though they will be if your PeriodicTable.txt
file has elements with increasing atomic number.
Since we know the exact number of elements in the PeriodicTable
and its something that doesn't change frequently, the filtering methods take constant time.
All you have to do now is create a proper PeriodicTable.txt
file which can then be used by the program.
Note: The PeriodicTable
class can be written in better ways as well. This is just an example. I can have it as Singleton. I can even have enum
of Element
with hardcoded values, but I think loading data from file will keep the code cleaner.
One can even augment the PeriodicTable
class with additional properties to each Element, by changing the process()
method accordingly, and changing the format of the text file based on the assumptions, and augmenting the Element
class, so that it can hold even more information.
Just for fun, following is a Singleton based solution:
// PeriodicTable.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class PeriodicTable
{
private static PeriodicTable periodicTable = new PeriodicTable();
private List<Element> elements;
private PeriodicTable()
{
try
{
elements = new ArrayList<>();
List<String> list = Files.readAllLines(Paths.get("PeriodicTable.txt"));
list.forEach(this::process);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static Element getElementByNumber(int atomicNumber)
{
return periodicTable.elements.stream().
filter(e -> e.atomicNumber == atomicNumber).
findFirst().orElse(null);
}
public static Element getElementBySymbol(String symbol)
{
return periodicTable.elements.stream().
filter(e -> e.symbol.equals(symbol)).
findFirst().orElse(null);
}
private void process(String line)
{
try (Scanner scanner = new Scanner(line))
{
int atomicNumber = scanner.nextInt();
String symbol = scanner.next();
String info = scanner.nextLine();
elements.add(new Element(atomicNumber, symbol, info));
}
}
private class Element
{
private String info;
private int atomicNumber;
private String symbol;
public Element(int atomicNumber, String symbol, String info)
{
this.atomicNumber = atomicNumber;
this.symbol = symbol;
this.info = info;
}
public String toString()
{
return "[ " + atomicNumber + " " + symbol + " " + info + " ]";
}
}
}
// Demo.java
public class Demo
{
public static void main(String[] args)
{
System.out.println(PeriodicTable.getElementByNumber(1));
System.out.println(PeriodicTable.getElementBySymbol("Li"));
}
}
Now you can use your PeriodicTable
safely and directly as shown in the Demo
method.
来源:https://stackoverflow.com/questions/22738023/data-structure-of-the-periodic-table-of-elements