我的目标是使用元素周期表(或列表)来获取有关Java中特定元素的信息。我想通过原子序数和符号搜索它(但该转换应该很简单)。元素周期表的数据结构
我在this JQuery plugin找到该信息。但它被存储为一个JSON文件。
硬编码信息似乎是最有效的(因为它不会经常更改并且由于性能原因),但是如何将JSON转换为硬编码的enum
?
我的目标是使用元素周期表(或列表)来获取有关Java中特定元素的信息。我想通过原子序数和符号搜索它(但该转换应该很简单)。元素周期表的数据结构
我在this JQuery plugin找到该信息。但它被存储为一个JSON文件。
硬编码信息似乎是最有效的(因为它不会经常更改并且由于性能原因),但是如何将JSON转换为硬编码的enum
?
由于:
枚举似乎是一个不错的选择:
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;
}
}
有一些Java功夫在这里,值得解释。该地图是把静态的内部(支架)类中,因此被初始化之前枚举实例初始化,这样,他们可以将自己添加到它。如果没有在内部静态类,它不会被初始化,因为第一件事就是枚举类初始化必须是实例,但静态内部类初始化上课之前被初始化。
这种方法意味着该实例不需要任何特别的顺序列出(它们可以是字母上市,或其他)。
假设你有一个PeriodicTable.txt
文件,格式如下:
ATOMIC_NUMBER SYMBOL OTHER_INFO
像:
1 H Hydrogen -> Lightest element
2 He Helium -> Second lightest element
3 Li Lithium -> Third lightest element
// and so on...
然后你就可以有一个像下面的一个相当简单的实现自己PeriodicTable
:
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 + " ]";
}
}
}
如果你看到,我已经创建了一个Element
类,其中包含元素的atomic number
,symbol
和info
,并且我在PeriodicTable
类中列出了elements
。
我从PeriodicTable.txt
文件中读取数据PeriodicTable
和通过适当地解析它并为每个行创建元件和将其添加到elements
处理文本文件的每一行。
我还添加了两种基于atomic number
和symbol
属性过滤元素的方法。
该代码适用于Java 8,因此您至少应该拥有该代码才能运行该代码,或者可以轻松地为此代码编写可在较早的JVM上运行的代码,尽管它不会像此代码那样紧凑。
由于PeriodicTable中的元素数量有限,因此我不打算按照它们的atomic number
排序元素,尽管它们会在您的PeriodicTable.txt
文件具有原子序数增加的元素时排列。
由于我们知道PeriodicTable
中元素的确切数量及其频繁变化的内容,因此过滤方法需要一定的时间。
您现在要做的就是创建一个合适的PeriodicTable.txt
文件,然后该文件就可以被程序使用。
注意:PeriodicTable
类也可以用更好的方式书写。这只是一个例子。我可以把它作为Singleton。我甚至可以在Element
的硬编码值enum
,但我认为从文件加载数据将保持代码更清洁。
一个甚至可以充实到PeriodicTable
类具有附加属性到每个元件中,通过相应地改变process()
方法,和改变所述文本文件的基础上的假设的格式,并增强所述Element
类,以便它可以容纳甚至更多信息。
只是为了好玩,下面是一个基于辛格尔顿的解决方案:
// 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"));
}
}
现在你可以使用你的PeriodicTable
安全直接如图所示Demo
方法。
非常感谢! “我认为从文件加载数据会使代码更清洁。”是的,但对性能有害吗? (好吧,不,没有,如果你始终保持在'PeriodicTable'对象的引用) – felixd
@felixd:你只需要加载'你的程序的执行过程中,一旦PeriodicTable'数据。这将只需要几毫秒。它在性能方面完全合适。文件阅读发生得非常快。 –
@felixd:可以将'PeriodicTable'类设置为Singleton,然后就不需要引用该对象。然后可以通过静态方法访问,通过原子序数和符号轻松查询元素。它的几行代码更改。 –
jQuery是一个JavaScript库和Java不运行。 Java不是JavaScript。 –
存在几个库来将'JSON'文件解析为'Hashmap'和'ArrayList'。 –
@Benjamin当然可以!我没有写任何其他的东西,对吧? – felixd