是否可以通过编程方式确定当前平台上可用的Java语言功能?

typ*_*cer 9 java

我想知道是否有一个Java API可以告诉你当前平台上是否有特定的语言功能(例如"钻石"操作符).

(换句话说,我正在尝试做的是类似于JavaScript中的"浏览器嗅探".)

这在元编程中非常方便(编写生成Java源代码的Java程序).

到目前为止,我发现的最佳解决方案是解析System.getProperty("java.specification.version")并检查它是否是引入此功能的版本,但我并不是100%确定此属性在所有JVM中都可用(或者甚至是否符合相同的语法在所有JVM中).这种方法的另一个小麻烦是你必须采取额外的步骤来查找哪个版本的Java引入了你感兴趣的语言功能.这不是什么大不了的事,因为这个信息很容易google,但理想情况下它会如果有一个可以轻松提供信息的API,那就太好了,例如:

code.append("Map<Integer, String> map = ");
if (javax.meta.JavaVersion.getCurrentVersion().supportsDiamond()) {
    code.append("new Map<>();");
} else {
    code.append("new Map<Integer, String>();");
}
Run Code Online (Sandbox Code Playgroud)

显然没有命名的软件包javax.meta,但我想知道是否已经有一个现有的解决方案来解决这个问题比解析"java.specification.version"属性更清晰.


更新:我刚刚意识到它Package#getSpecificationVersion()也提供了相同的值,System.getProperty("java.specification.version")但可能更可靠,因为系统属性是可变的.换句话说,获取Java规范版本的最佳方法可能是调用Package#getSpecificationVersion()任何"内置"包.例如:String.class.getPackage().getSpecificationVersion()

小智 3

一个功能可能是:JDK 10

  1. 方法 :Optional.orElseThrow()
  2. API:用于创建不可修改集合的API
  3. 系统属性:例如,禁用 JRE 上次使用情况跟踪
  4. GC增强(全并行)
  5. Javadoc 支持:(对于多个样式表)

它也可能是一个功能的删除:也在 Java 10 中

  1. 取消对使用旧 LookAndFeel 的支持
  2. 去除Runtime.getLocalizedInputStreamgetLocalizedOutputStream方法
  3. 等等..

因此,如果新功能存在或已被删除,则很难以check编程discover方式进行识别,除非您知道自己在寻找什么,否则它需要由 Oracle 本身以文档、功能名称和描述的形式提供。

如果我们要为此创建 API,我们必须首先从 Oracle 文档获取列表,然后对每个功能进行必要的检查以发现当前版本或是否受支持。

以下是以编程方式检查编译器的特定功能的示例。

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Arrays;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject.Kind;

public class CompileSourceInMemory {
  public static void main(String args[]) throws IOException {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

    StringWriter writer = new StringWriter();
    PrintWriter out = new PrintWriter(writer);
    out.println("public class HelloWorld {");
    out.println("  public static void main(String args[]) {");
    out.println("    System.out.println(\"This is in another java file\");");    
    out.println("  }");
    out.println("}");
    out.close();
    JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString());

    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

    boolean success = task.call();
    for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
      System.out.println(diagnostic.getCode());
      System.out.println(diagnostic.getKind());
      System.out.println(diagnostic.getPosition());
      System.out.println(diagnostic.getStartPosition());
      System.out.println(diagnostic.getEndPosition());
      System.out.println(diagnostic.getSource());
      System.out.println(diagnostic.getMessage(null));

    }
    System.out.println("Success: " + success);

    if (success) {
      try {
        Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class })
            .invoke(null, new Object[] { null });
      } catch (ClassNotFoundException e) {
        System.err.println("Class not found: " + e);
      } catch (NoSuchMethodException e) {
        System.err.println("No such method: " + e);
      } catch (IllegalAccessException e) {
        System.err.println("Illegal access: " + e);
      } catch (InvocationTargetException e) {
        System.err.println("Invocation target: " + e);
      }
    }
  }
}

class JavaSourceFromString extends SimpleJavaFileObject {
  final String code;

  JavaSourceFromString(String name, String code) {
    super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE);
    this.code = code;
  }

  @Override
  public CharSequence getCharContent(boolean ignoreEncodingErrors) {
    return code;
  }
}
Run Code Online (Sandbox Code Playgroud)

查看 JDK 10功能