2014-03-29 40 views
0

我的目标是使用元素周期表(或列表)来获取有关Java中特定元素的信息。我想通过原子序数和符号搜索它(但该转换应该很简单)。元素周期表的数据结构

我在this JQuery plugin找到该信息。但它被存储为一个JSON文件。

硬编码信息似乎是最有效的(因为它不会经常更改并且由于性能原因),但是如何将JSON转换为硬编码的enum

+2

jQuery是一个JavaScript库和Java不运行。 Java不是JavaScript。 –

+0

存在几个库来将'JSON'文件解析为'Hashmap'和'ArrayList'。 –

+0

@Benjamin当然可以!我没有写任何其他的东西,对吧? – felixd

回答

5

由于:

  • 关于元素的信息是完全静态的
  • 每个元素符号是字母数字
  • 新元素的发现是既有难得的和不相关(因为他们是非常不稳定)

枚举似乎是一个不错的选择:

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功夫在这里,值得解释。该地图是把静态的内部(支架)类中,因此被初始化之前枚举实例初始化,这样,他们可以将自己添加到它。如果没有在内部静态类,它不会被初始化,因为第一件事就是枚举类初始化必须是实例,但静态内部类初始化上课之前被初始化。

这种方法意味着该实例不需要任何特别的顺序列出(它们可以是字母上市,或其他)。

+0

好的,这似乎是逻辑,但我如何取代“...... 90+其他”?这是这里有趣的部分。 – felixd

+0

如何按原子序数搜索? – felixd

+1

@felixd查看编辑答案查看原子序数。关于“其他90+” - 谷歌它并输入(只需要做到这一点) – Bohemian

2

假设你有一个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,symbolinfo,并且我在PeriodicTable类中列出了elements

我从PeriodicTable.txt文件中读取数据PeriodicTable和通过适当地解析它并为每个行创建元件和将其添加到elements处理文本文件的每一行。

我还添加了两种基于atomic numbersymbol属性过滤元素的方法。

该代码适用于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方法。

+0

非常感谢! “我认为从文件加载数据会使代码更清洁。”是的,但对性能有害吗? (好吧,不,没有,如果你始终保持在'PeriodicTable'对象的引用) – felixd

+1

@felixd:你只需要加载'你的程序的执行过程中,一旦PeriodicTable'数据。这将只需要几毫秒。它在性能方面完全合适。文件阅读发生得非常快。 –

+1

@felixd:可以将'PeriodicTable'类设置为Singleton,然后就不需要引用该对象。然后可以通过静态方法访问,通过原子序数和符号轻松查询元素。它的几行代码更改。 –