我想要使用 java。的文本。规范化器 类Java1.6做Unicode正常化,但我的代码拥有能够运行的Java1.5.

我不介意,如果上运行的代码1.5不正常化,但我不想给 NoClassDefFoundErrors或 ClassNotFoundExceptions当运行。

什么是最好的方式来实现这一目标?

有帮助吗?

解决方案

这样做的通常的方法是通过反射,即不直接指所讨论的类,但是编程调用它。这可以让你捕捉异常优雅如果有问题的代码不存在,并且或者忽略它,或尝试别的东西。反射抛出ClassNotFoundException,这是一个很好的正常的异常,而不是NoClassDefFoundError,这是一种位可怕。

java.text.Normalizer的情况下,这应该是很容易的,因为它只是一对夫妇的静态方法,并且便于通过反射调用。

其他提示

public interface NfcNormalizer
{
  public String normalize(String str);
}

public class IdentityNfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return str;
  }
}

public class JDK16NfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return Normalizer.normalize(str, Normalizer.Form.NFC);
  }
}

在客户机代码:

NfcNormalizer normalizer;
try
{
  normalizer = Class.forName("JDK16NfcNormalizer").newInstance();
}
catch(Exception e)
{
  normalizer = new IdentityNfcNormalizer();
}
  

如果在1.5上运行没有做归一化的代码,我不介意,但我不希望它给NoClassDefFoundErrors或ClassNotFoundExceptions在运行时。

如果你想避免反射,你可以实际赶上这些错误。

这样,您就可以编译对闪亮的新类具有的Java6编译器,它仍然可以工作(如“没有做任何事情,也不会崩溃”)在Java5的。

您也可以结合这两种方法,并检查是否存在类使用反射,如果它继续调用它无反射的方式。这是安德鲁公司的解决方案正在做。

如果您还需要的编译的上Java5的,那么你就需要去反思的所有道路。

我也有同样的需求,因为我们的代码需要在 Java 1.2 以来的所有 Java 版本上运行,但有些代码需要利用较新的 API(如果可用)。

在使用反射获取 Method 对象并动态调用它们的各种排列之后,一般来说,我选择了最好的包装器样式方法(尽管在某些情况下,仅将反射的 Method 存储为静态并调用它更好 - 这取决于) 。

以下是一个示例“系统实用程序”类,它在运行早期版本时公开了 Java 5 的某些较新的 API - 相同的原则也适用于早期 JVM 中的 Java 6。此示例使用 Singleton,但如果底层 API 需要,可以轻松实例化多个对象。

有两个类:

  • 系统工具
  • 系统实用程序_J5

如果运行时 JVM 是 Java 5 或更高版本,则使用后者。否则,将使用 SysUtil 中的默认实现中兼容的后备方法,该实现仅使用 Java 4 或更早的 API。每个类都使用特定版本的编译器进行编译,因此 Java 4 类中不会意外使用 Java 5+ API:

SysUtil(使用 Java 4 编译器编译)

import java.io.*;
import java.util.*;

/**
 * Masks direct use of select system methods to allow transparent use of facilities only
 * available in Java 5+ JVM.
 *
 * Threading Design : [ ] Single Threaded  [x] Threadsafe  [ ] Immutable  [ ] Isolated
 */

public class SysUtil
extends Object
{

/** Package protected to allow subclass SysUtil_J5 to invoke it. */
SysUtil() {
    super();
    }

// *****************************************************************************
// INSTANCE METHODS - SUBCLASS OVERRIDE REQUIRED
// *****************************************************************************

/** Package protected to allow subclass SysUtil_J5 to override it. */
int availableProcessors() {
    return 1;
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long milliTime() {
    return System.currentTimeMillis();
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long nanoTime() {
    return (System.currentTimeMillis()*1000000L);
    }

// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************

static private final SysUtil            INSTANCE;
static {
    SysUtil                             instance=null;

    try                  { instance=(SysUtil)Class.forName("SysUtil_J5").newInstance(); } // can't use new SysUtil_J5() - compiler reports "class file has wrong version 49.0, should be 47.0"
    catch(Throwable thr) { instance=new SysUtil();                                                                    }
    INSTANCE=instance;
    }

// *****************************************************************************
// STATIC METHODS
// *****************************************************************************

/**
 * Returns the number of processors available to the Java virtual machine.
 * <p>
 * This value may change during a particular invocation of the virtual machine. Applications that are sensitive to the
 * number of available processors should therefore occasionally poll this property and adjust their resource usage
 * appropriately.
 */
static public int getAvailableProcessors() {
    return INSTANCE.availableProcessors();
    }

/**
 * Returns the current time in milliseconds.
 * <p>
 * Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the
 * underlying operating system and may be larger. For example, many operating systems measure time in units of tens of
 * milliseconds.
 * <p>
 * See the description of the class Date for a discussion of slight discrepancies that may arise between "computer time"
 * and coordinated universal time (UTC).
 * <p>
 * @return         The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
 */
static public long getMilliTime() {
    return INSTANCE.milliTime();
    }

/**
 * Returns the current value of the most precise available system timer, in nanoseconds.
 * <p>
 * This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock
 * time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values
 * may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees
 * are made about how frequently values change. Differences in successive calls that span greater than approximately 292
 * years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.
 * <p>
 * For example, to measure how long some code takes to execute:
 * <p><pre>
 *    long startTime = SysUtil.getNanoTime();
 *    // ... the code being measured ...
 *    long estimatedTime = SysUtil.getNanoTime() - startTime;
 * </pre>
 * <p>
 * @return          The current value of the system timer, in nanoseconds.
 */
static public long getNanoTime() {
    return INSTANCE.nanoTime();
    }

} // END PUBLIC CLASS

SysUtil_J5(使用Java 5编译器编译)

import java.util.*;

class SysUtil_J5
extends SysUtil
{

private final Runtime                   runtime;

SysUtil_J5() {
    super();

    runtime=Runtime.getRuntime();
    }

// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************

int availableProcessors() {
    return runtime.availableProcessors();
    }

long milliTime() {
    return System.currentTimeMillis();
    }

long nanoTime() {
    return System.nanoTime();
    }

} // END PUBLIC CLASS

检查/使用/修改课 信息。olteanu.工具.TextNormalizer 在Phramer项目(http://sourceforge.net/projects/phramer/ ,www.phramer.org )-代码是BSD获得许可。

这些代码可以编制在Java5和运行两个在Java5或Java6(或未来的Java版本)。此外,它可以编制在Java6和运行在Java5(如果有正确的"目标",特码的兼容性)或Java6或其他任何未来版本。

恕我直言这完全解决你的问题-你是免费汇编在任何Java5+平台,而你能得到的功能所需(归一化)在任何Java5+平台(*)

(*)太阳Java5解决方案的正常化将最有可能不会存在于所有Java5的实现,所以在最糟糕情况你最终会得到一个ClassNotFoundException当你呼叫getNormalizationStringFilter()方法。

    String str = "éèà";
    try {
        Class c = Class.forName("java.text.Normalizer");
        Class f = Class.forName("java.text.Normalizer$Form");
        Field ff = f.getField("NFD");
        Method m = c.getDeclaredMethod("normalize", new Class[]{java.lang.CharSequence.class,f});
        temp = (String) m.invoke(null, new Object[]{str,ff.get(null)});
    } catch (Throwable e) {
        System.err.println("Unsupported Normalisation method (jvm <1.6)");
    }
    System.out.println(temp+" should produce [eea]");

这是老问题,但仍实际。我发现未在答案中提到的一些可能性。

一般建议使用反射在一些其他的答案被示出在这里。但是,如果你不想把乱七八糟的代码,你可以使用 ICU4J库。它包含执行相同的工作作为java.text.Normalizer / sun.text.Normalizer com.ibm.icu.text.Normalizer方法normalize()类。 ICU库有(应该有)自己的实现正规化的,所以你可以与图书馆共享您的项目,这应该是java无关。结果 缺点是ICU库是相当大的。

如果您在使用正规化类只是从字符串去除重音/音调符号,这里还有另一种方式。可以使用阿帕奇公地Lang库(版本3)包含与方法StringUtils stripAccents()

String noAccentsString = org.apache.commons.lang3.StringUtils.stripAccents(s);

Lang3库可能使用反射根据Java版本来调用适当的正规化。因此,优点是,你不必乱反射在你的代码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top