2 *******************************************************************************
3 * Copyright (C) 1996-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.text;
10 import java.lang.ref.SoftReference;
11 import java.text.CharacterIterator;
12 import java.text.StringCharacterIterator;
13 import java.util.Locale;
14 import java.util.MissingResourceException;
16 import com.ibm.icu.impl.ICUDebug;
17 import com.ibm.icu.util.ULocale;
20 * {@icuenhanced java.text.BreakIterator}.{@icu _usage_}
22 * <p>A class that locates boundaries in text. This class defines a protocol for
23 * objects that break up a piece of natural-language text according to a set
24 * of criteria. Instances or subclasses of BreakIterator can be provided, for
25 * example, to break a piece of text into words, sentences, or logical characters
26 * according to the conventions of some language or group of languages.
28 * We provide five built-in types of BreakIterator:
29 * <ul><li>getTitleInstance() returns a BreakIterator that locates boundaries
30 * between title breaks.
31 * <li>getSentenceInstance() returns a BreakIterator that locates boundaries
32 * between sentences. This is useful for triple-click selection, for example.
33 * <li>getWordInstance() returns a BreakIterator that locates boundaries between
34 * words. This is useful for double-click selection or "find whole words" searches.
35 * This type of BreakIterator makes sure there is a boundary position at the
36 * beginning and end of each legal word. (Numbers count as words, too.) Whitespace
37 * and punctuation are kept separate from real words.
38 * <li>getLineInstance() returns a BreakIterator that locates positions where it is
39 * legal for a text editor to wrap lines. This is similar to word breaking, but
40 * not the same: punctuation and whitespace are generally kept with words (you don't
41 * want a line to start with whitespace, for example), and some special characters
42 * can force a position to be considered a line-break position or prevent a position
43 * from being a line-break position.
44 * <li>getCharacterInstance() returns a BreakIterator that locates boundaries between
45 * logical characters. Because of the structure of the Unicode encoding, a logical
46 * character may be stored internally as more than one Unicode code point. (A with an
47 * umlaut may be stored as an a followed by a separate combining umlaut character,
48 * for example, but the user still thinks of it as one character.) This iterator allows
49 * various processes (especially text editors) to treat as characters the units of text
50 * that a user would think of as characters, rather than the units of text that the
51 * computer sees as "characters".</ul>
53 * BreakIterator's interface follows an "iterator" model (hence the name), meaning it
54 * has a concept of a "current position" and methods like first(), last(), next(),
55 * and previous() that update the current position. All BreakIterators uphold the
56 * following invariants:
57 * <ul><li>The beginning and end of the text are always treated as boundary positions.
58 * <li>The current position of the iterator is always a boundary position (random-
59 * access methods move the iterator to the nearest boundary position before or
60 * after the specified position, not _to_ the specified position).
61 * <li>DONE is used as a flag to indicate when iteration has stopped. DONE is only
62 * returned when the current position is the end of the text and the user calls next(),
63 * or when the current position is the beginning of the text and the user calls
65 * <li>Break positions are numbered by the positions of the characters that follow
66 * them. Thus, under normal circumstances, the position before the first character
67 * is 0, the position after the first character is 1, and the position after the
68 * last character is 1 plus the length of the string.
69 * <li>The client can change the position of an iterator, or the text it analyzes,
70 * at will, but cannot change the behavior. If the user wants different behavior, he
71 * must instantiate a new iterator.</ul>
73 * BreakIterator accesses the text it analyzes through a CharacterIterator, which makes
74 * it possible to use BreakIterator to analyze text in any text-storage vehicle that
75 * provides a CharacterIterator interface.
77 * <b>Note:</b> Some types of BreakIterator can take a long time to create, and
78 * instances of BreakIterator are not currently cached by the system. For
79 * optimal performance, keep instances of BreakIterator around as long as makes
80 * sense. For example, when word-wrapping a document, don't create and destroy a
81 * new BreakIterator for each line. Create one break iterator for the whole document
82 * (or whatever stretch of text you're wrapping) and use it to do the whole job of
86 * <strong>Examples</strong>:<P>
87 * Creating and using text boundaries
90 * public static void main(String args[]) {
91 * if (args.length == 1) {
92 * String stringToExamine = args[0];
93 * //print each word in order
94 * BreakIterator boundary = BreakIterator.getWordInstance();
95 * boundary.setText(stringToExamine);
96 * printEachForward(boundary, stringToExamine);
97 * //print each sentence in reverse order
98 * boundary = BreakIterator.getSentenceInstance(Locale.US);
99 * boundary.setText(stringToExamine);
100 * printEachBackward(boundary, stringToExamine);
101 * printFirst(boundary, stringToExamine);
102 * printLast(boundary, stringToExamine);
108 * Print each element in order
111 * public static void printEachForward(BreakIterator boundary, String source) {
112 * int start = boundary.first();
113 * for (int end = boundary.next();
114 * end != BreakIterator.DONE;
115 * start = end, end = boundary.next()) {
116 * System.out.println(source.substring(start,end));
122 * Print each element in reverse order
125 * public static void printEachBackward(BreakIterator boundary, String source) {
126 * int end = boundary.last();
127 * for (int start = boundary.previous();
128 * start != BreakIterator.DONE;
129 * end = start, start = boundary.previous()) {
130 * System.out.println(source.substring(start,end));
136 * Print first element
139 * public static void printFirst(BreakIterator boundary, String source) {
140 * int start = boundary.first();
141 * int end = boundary.next();
142 * System.out.println(source.substring(start,end));
150 * public static void printLast(BreakIterator boundary, String source) {
151 * int end = boundary.last();
152 * int start = boundary.previous();
153 * System.out.println(source.substring(start,end));
158 * Print the element at a specified position
161 * public static void printAt(BreakIterator boundary, int pos, String source) {
162 * int end = boundary.following(pos);
163 * int start = boundary.previous();
164 * System.out.println(source.substring(start,end));
172 * public static int nextWordStartAfter(int pos, String text) {
173 * BreakIterator wb = BreakIterator.getWordInstance();
175 * int last = wb.following(pos);
176 * int current = wb.next();
177 * while (current != BreakIterator.DONE) {
178 * for (int p = last; p < current; p++) {
179 * if (Character.isLetter(text.charAt(p)))
183 * current = wb.next();
185 * return BreakIterator.DONE;
188 * (The iterator returned by BreakIterator.getWordInstance() is unique in that
189 * the break positions it returns don't represent both the start and end of the
190 * thing being iterated over. That is, a sentence-break iterator returns breaks
191 * that each represent the end of one sentence and the beginning of the next.
192 * With the word-break iterator, the characters between two boundaries might be a
193 * word, or they might be the punctuation or whitespace between two words. The
194 * above code uses a simple heuristic to determine which boundary is the beginning
195 * of a word: If the characters between this boundary and the next boundary
196 * include at least one letter (this can be an alphabetical letter, a CJK ideograph,
197 * a Hangul syllable, a Kana character, etc.), then the text between this boundary
198 * and the next is a word; otherwise, it's the material between words.)
201 * @see CharacterIterator
206 public abstract class BreakIterator implements Cloneable
209 private static final boolean DEBUG = ICUDebug.enabled("breakiterator");
212 * Default constructor. There is no state that is carried by this abstract
216 protected BreakIterator()
221 * Clone method. Creates another BreakIterator with the same behavior and
222 * current state as this one.
226 public Object clone()
229 return super.clone();
231 catch (CloneNotSupportedException e) {
233 throw new IllegalStateException();
239 * DONE is returned by previous() and next() after all valid
240 * boundaries have been returned.
243 public static final int DONE = -1;
246 * Return the first boundary position. This is always the beginning
247 * index of the text this iterator iterates over. For example, if
248 * the iterator iterates over a whole string, this function will
249 * always return 0. This function also updates the iteration position
250 * to point to the beginning of the text.
251 * @return The character offset of the beginning of the stretch of text
255 public abstract int first();
258 * Return the last boundary position. This is always the "past-the-end"
259 * index of the text this iterator iterates over. For example, if the
260 * iterator iterates over a whole string (call it "text"), this function
261 * will always return text.length(). This function also updated the
262 * iteration position to point to the end of the text.
263 * @return The character offset of the end of the stretch of text
267 public abstract int last();
270 * Advances the specified number of steps forward in the text (a negative
271 * number, therefore, advances backwards). If this causes the iterator
272 * to advance off either end of the text, this function returns DONE;
273 * otherwise, this function returns the position of the appropriate
274 * boundary. Calling this function is equivalent to calling next() or
275 * previous() n times.
276 * @param n The number of boundaries to advance over (if positive, moves
277 * forward; if negative, moves backwards).
278 * @return The position of the boundary n boundaries from the current
279 * iteration position, or DONE if moving n boundaries causes the iterator
280 * to advance off either end of the text.
283 public abstract int next(int n);
286 * Advances the iterator forward one boundary. The current iteration
287 * position is updated to point to the next boundary position after the
288 * current position, and this is also the value that is returned. If
289 * the current position is equal to the value returned by last(), or to
290 * DONE, this function returns DONE and sets the current position to
292 * @return The position of the first boundary position following the
293 * iteration position.
296 public abstract int next();
299 * Advances the iterator backward one boundary. The current iteration
300 * position is updated to point to the last boundary position before
301 * the current position, and this is also the value that is returned. If
302 * the current position is equal to the value returned by first(), or to
303 * DONE, this function returns DONE and sets the current position to
305 * @return The position of the last boundary position preceding the
306 * iteration position.
309 public abstract int previous();
312 * Sets the iterator's current iteration position to be the first
313 * boundary position following the specified position. (Whether the
314 * specified position is itself a boundary position or not doesn't
315 * matter-- this function always moves the iteration position to the
316 * first boundary after the specified position.) If the specified
317 * position is the past-the-end position, returns DONE.
318 * @param offset The character position to start searching from.
319 * @return The position of the first boundary position following
320 * "offset" (whether or not "offset" itself is a boundary position),
321 * or DONE if "offset" is the past-the-end offset.
324 public abstract int following(int offset);
327 * Sets the iterator's current iteration position to be the last
328 * boundary position preceding the specified position. (Whether the
329 * specified position is itself a boundary position or not doesn't
330 * matter-- this function always moves the iteration position to the
331 * last boundary before the specified position.) If the specified
332 * position is the starting position, returns DONE.
333 * @param offset The character position to start searching from.
334 * @return The position of the last boundary position preceding
335 * "offset" (whether of not "offset" itself is a boundary position),
336 * or DONE if "offset" is the starting offset of the iterator.
339 public int preceding(int offset) {
340 // NOTE: This implementation is here solely because we can't add new
341 // abstract methods to an existing class. There is almost ALWAYS a
342 // better, faster way to do this.
343 int pos = following(offset);
344 while (pos >= offset && pos != DONE)
350 * Return true if the specfied position is a boundary position. If the
351 * function returns true, the current iteration position is set to the
352 * specified position; if the function returns false, the current
353 * iteration position is set as though following() had been called.
354 * @param offset the offset to check.
355 * @return True if "offset" is a boundary position.
358 public boolean isBoundary(int offset) {
359 // Again, this is the default implementation, which is provided solely because
360 // we couldn't add a new abstract method to an existing class. The real
361 // implementations will usually need to do a little more work.
366 return following(offset - 1) == offset;
370 * Return the iterator's current position.
371 * @return The iterator's current position.
374 public abstract int current();
377 * Returns a CharacterIterator over the text being analyzed.
378 * For at least some subclasses of BreakIterator, this is a reference
379 * to the <b>actual iterator being used</b> by the BreakIterator,
380 * and therefore, this function's return value should be treated as
381 * <tt>const</tt>. No guarantees are made about the current position
382 * of this iterator when it is returned. If you need to move that
383 * position to examine the text, clone this function's return value first.
384 * @return A CharacterIterator over the text being analyzed.
387 public abstract CharacterIterator getText();
390 * Sets the iterator to analyze a new piece of text. The new
391 * piece of text is passed in as a String, and the current
392 * iteration position is reset to the beginning of the string.
393 * (The old text is dropped.)
394 * @param newText A String containing the text to analyze with
395 * this BreakIterator.
398 public void setText(String newText)
400 setText(new StringCharacterIterator(newText));
404 * Sets the iterator to analyze a new piece of text. The
405 * BreakIterator is passed a CharacterIterator through which
406 * it will access the text itself. The current iteration
407 * position is reset to the CharacterIterator's start index.
408 * (The old iterator is dropped.)
409 * @param newText A CharacterIterator referring to the text
410 * to analyze with this BreakIterator (the iterator's current
411 * position is ignored, but its other state is significant).
414 public abstract void setText(CharacterIterator newText);
420 public static final int KIND_CHARACTER = 0;
425 public static final int KIND_WORD = 1;
430 public static final int KIND_LINE = 2;
435 public static final int KIND_SENTENCE = 3;
440 public static final int KIND_TITLE = 4;
445 private static final int KIND_COUNT = 5;
447 private static final SoftReference<?>[] iterCache = new SoftReference<?>[5];
450 * Returns a new instance of BreakIterator that locates word boundaries.
451 * This function assumes that the text being analyzed is in the default
453 * @return An instance of BreakIterator that locates word boundaries.
456 public static BreakIterator getWordInstance()
458 return getWordInstance(ULocale.getDefault());
462 * Returns a new instance of BreakIterator that locates word boundaries.
463 * @param where A locale specifying the language of the text to be
465 * @return An instance of BreakIterator that locates word boundaries.
468 public static BreakIterator getWordInstance(Locale where)
470 return getBreakInstance(ULocale.forLocale(where), KIND_WORD);
474 * {@icu} Returns a new instance of BreakIterator that locates word boundaries.
475 * @param where A locale specifying the language of the text to be
477 * @return An instance of BreakIterator that locates word boundaries.
480 public static BreakIterator getWordInstance(ULocale where)
482 return getBreakInstance(where, KIND_WORD);
486 * Returns a new instance of BreakIterator that locates legal line-
487 * wrapping positions. This function assumes the text being broken
488 * is in the default locale's language.
489 * @return A new instance of BreakIterator that locates legal
490 * line-wrapping positions.
493 public static BreakIterator getLineInstance()
495 return getLineInstance(ULocale.getDefault());
499 * Returns a new instance of BreakIterator that locates legal line-
500 * wrapping positions.
501 * @param where A Locale specifying the language of the text being broken.
502 * @return A new instance of BreakIterator that locates legal
503 * line-wrapping positions.
506 public static BreakIterator getLineInstance(Locale where)
508 return getBreakInstance(ULocale.forLocale(where), KIND_LINE);
512 * {@icu} Returns a new instance of BreakIterator that locates legal line-
513 * wrapping positions.
514 * @param where A Locale specifying the language of the text being broken.
515 * @return A new instance of BreakIterator that locates legal
516 * line-wrapping positions.
519 public static BreakIterator getLineInstance(ULocale where)
521 return getBreakInstance(where, KIND_LINE);
525 * Returns a new instance of BreakIterator that locates logical-character
526 * boundaries. This function assumes that the text being analyzed is
527 * in the default locale's language.
528 * @return A new instance of BreakIterator that locates logical-character
532 public static BreakIterator getCharacterInstance()
534 return getCharacterInstance(ULocale.getDefault());
538 * Returns a new instance of BreakIterator that locates logical-character
540 * @param where A Locale specifying the language of the text being analyzed.
541 * @return A new instance of BreakIterator that locates logical-character
545 public static BreakIterator getCharacterInstance(Locale where)
547 return getBreakInstance(ULocale.forLocale(where), KIND_CHARACTER);
551 * {@icu} Returns a new instance of BreakIterator that locates logical-character
553 * @param where A Locale specifying the language of the text being analyzed.
554 * @return A new instance of BreakIterator that locates logical-character
558 public static BreakIterator getCharacterInstance(ULocale where)
560 return getBreakInstance(where, KIND_CHARACTER);
564 * Returns a new instance of BreakIterator that locates sentence boundaries.
565 * This function assumes the text being analyzed is in the default locale's
567 * @return A new instance of BreakIterator that locates sentence boundaries.
570 public static BreakIterator getSentenceInstance()
572 return getSentenceInstance(ULocale.getDefault());
576 * Returns a new instance of BreakIterator that locates sentence boundaries.
577 * @param where A Locale specifying the language of the text being analyzed.
578 * @return A new instance of BreakIterator that locates sentence boundaries.
581 public static BreakIterator getSentenceInstance(Locale where)
583 return getBreakInstance(ULocale.forLocale(where), KIND_SENTENCE);
587 * {@icu} Returns a new instance of BreakIterator that locates sentence boundaries.
588 * @param where A Locale specifying the language of the text being analyzed.
589 * @return A new instance of BreakIterator that locates sentence boundaries.
592 public static BreakIterator getSentenceInstance(ULocale where)
594 return getBreakInstance(where, KIND_SENTENCE);
598 * {@icu} Returns a new instance of BreakIterator that locates title boundaries.
599 * This function assumes the text being analyzed is in the default locale's
600 * language. The iterator returned locates title boundaries as described for
601 * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
602 * please use a word boundary iterator. {@link #getWordInstance}
603 * @return A new instance of BreakIterator that locates title boundaries.
606 public static BreakIterator getTitleInstance()
608 return getTitleInstance(ULocale.getDefault());
612 * {@icu} Returns a new instance of BreakIterator that locates title boundaries.
613 * The iterator returned locates title boundaries as described for
614 * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
615 * please use Word Boundary iterator.{@link #getWordInstance}
616 * @param where A Locale specifying the language of the text being analyzed.
617 * @return A new instance of BreakIterator that locates title boundaries.
620 public static BreakIterator getTitleInstance(Locale where)
622 return getBreakInstance(ULocale.forLocale(where), KIND_TITLE);
626 * {@icu} Returns a new instance of BreakIterator that locates title boundaries.
627 * The iterator returned locates title boundaries as described for
628 * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
629 * please use Word Boundary iterator.{@link #getWordInstance}
630 * @param where A Locale specifying the language of the text being analyzed.
631 * @return A new instance of BreakIterator that locates title boundaries.
634 public static BreakIterator getTitleInstance(ULocale where)
636 return getBreakInstance(where, KIND_TITLE);
640 * {@icu} Registers a new break iterator of the indicated kind, to use in the given
641 * locale. Clones of the iterator will be returned if a request for a break iterator
642 * of the given kind matches or falls back to this locale.
643 * @param iter the BreakIterator instance to adopt.
644 * @param locale the Locale for which this instance is to be registered
645 * @param kind the type of iterator for which this instance is to be registered
646 * @return a registry key that can be used to unregister this instance
649 public static Object registerInstance(BreakIterator iter, Locale locale, int kind) {
650 return registerInstance(iter, ULocale.forLocale(locale), kind);
654 * {@icu} Registers a new break iterator of the indicated kind, to use in the given
655 * locale. Clones of the iterator will be returned if a request for a break iterator
656 * of the given kind matches or falls back to this locale.
657 * @param iter the BreakIterator instance to adopt.
658 * @param locale the Locale for which this instance is to be registered
659 * @param kind the type of iterator for which this instance is to be registered
660 * @return a registry key that can be used to unregister this instance
663 public static Object registerInstance(BreakIterator iter, ULocale locale, int kind) {
664 // If the registered object matches the one in the cache, then
665 // flush the cached object.
666 if (iterCache[kind] != null) {
667 BreakIteratorCache cache = (BreakIteratorCache) iterCache[kind].get();
669 if (cache.getLocale().equals(locale)) {
670 iterCache[kind] = null;
674 return getShim().registerInstance(iter, locale, kind);
678 * {@icu} Unregisters a previously-registered BreakIterator using the key returned
679 * from the register call. Key becomes invalid after this call and should not be used
681 * @param key the registry key returned by a previous call to registerInstance
682 * @return true if the iterator for the key was successfully unregistered
685 public static boolean unregister(Object key) {
687 throw new IllegalArgumentException("registry key must not be null");
689 // TODO: we don't do code coverage for the following lines
690 // because in getBreakInstance we always instantiate the shim,
691 // and test execution is such that we always instantiate a
692 // breakiterator before we get to the break iterator tests.
693 // this is for modularization, and we could remove the
694 // dependencies in getBreakInstance by rewriting part of the
695 // LocaleData code, or perhaps by accepting it into the
699 // Unfortunately, we don't know what is being unregistered
700 // -- what `kind' and what locale -- so we flush all
701 // caches. This is safe but inefficient if people are
702 // actively registering and unregistering.
703 for (int kind=0; kind<KIND_COUNT; ++kind) {
704 iterCache[kind] = null;
706 return shim.unregister(key);
712 // end of registration
715 * Returns a particular kind of BreakIterator for a locale.
716 * Avoids writing a switch statement with getXYZInstance(where) calls.
718 * @deprecated This API is ICU internal only.
720 public static BreakIterator getBreakInstance(ULocale where, int kind) {
722 if (iterCache[kind] != null) {
723 BreakIteratorCache cache = (BreakIteratorCache)iterCache[kind].get();
725 if (cache.getLocale().equals(where)) {
726 return cache.createBreakInstance();
731 // sigh, all to avoid linking in ICULocaleData...
732 BreakIterator result = getShim().createBreakIterator(where, kind);
734 BreakIteratorCache cache = new BreakIteratorCache(where, result);
735 iterCache[kind] = new SoftReference<BreakIteratorCache>(cache);
741 * Returns a list of locales for which BreakIterators can be used.
742 * @return An array of Locales. All of the locales in the array can
743 * be used when creating a BreakIterator.
746 public static synchronized Locale[] getAvailableLocales()
748 // to avoid linking ICULocaleData
749 return getShim().getAvailableLocales();
753 * {@icu} Returns a list of locales for which BreakIterators can be used.
754 * @return An array of Locales. All of the locales in the array can
755 * be used when creating a BreakIterator.
756 * @draft ICU 3.2 (retain)
757 * @provisional This API might change or be removed in a future release.
759 public static synchronized ULocale[] getAvailableULocales()
761 // to avoid linking ICULocaleData
762 return getShim().getAvailableULocales();
765 private static final class BreakIteratorCache {
767 private BreakIterator iter;
768 private ULocale where;
770 BreakIteratorCache(ULocale where, BreakIterator iter) {
772 this.iter = (BreakIterator) iter.clone();
775 ULocale getLocale() {
779 BreakIterator createBreakInstance() {
780 return (BreakIterator) iter.clone();
784 static abstract class BreakIteratorServiceShim {
785 public abstract Object registerInstance(BreakIterator iter, ULocale l, int k);
786 public abstract boolean unregister(Object key);
787 public abstract Locale[] getAvailableLocales();
788 public abstract ULocale[] getAvailableULocales();
789 public abstract BreakIterator createBreakIterator(ULocale l, int k);
792 private static BreakIteratorServiceShim shim;
793 private static BreakIteratorServiceShim getShim() {
794 // Note: this instantiation is safe on loose-memory-model configurations
795 // despite lack of synchronization, since the shim instance has no state--
796 // it's all in the class init. The worst problem is we might instantiate
797 // two shim instances, but they'll share the same state so that's ok.
800 Class<?> cls = Class.forName("com.ibm.icu.text.BreakIteratorFactory");
801 shim = (BreakIteratorServiceShim)cls.newInstance();
803 catch (MissingResourceException e)
807 catch (Exception e) {
812 throw new RuntimeException(e.getMessage());
819 // -------- BEGIN ULocale boilerplate --------
822 * {@icu} Returns the locale that was used to create this object, or null.
823 * This may may differ from the locale requested at the time of
824 * this object's creation. For example, if an object is created
825 * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
826 * drawn from <tt>en</tt> (the <i>actual</i> locale), and
827 * <tt>en_US</tt> may be the most specific locale that exists (the
828 * <i>valid</i> locale).
830 * <p>Note: The <i>actual</i> locale is returned correctly, but the <i>valid</i>
831 * locale is not, in most cases.
832 * @param type type of information requested, either {@link
833 * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
834 * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
835 * @return the information specified by <i>type</i>, or null if
836 * this object was not constructed from locale data.
837 * @see com.ibm.icu.util.ULocale
838 * @see com.ibm.icu.util.ULocale#VALID_LOCALE
839 * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
840 * @draft ICU 2.8 (retain)
841 * @provisional This API might change or be removed in a future release.
843 public final ULocale getLocale(ULocale.Type type) {
844 return type == ULocale.ACTUAL_LOCALE ?
845 this.actualLocale : this.validLocale;
849 * Set information about the locales that were used to create this
850 * object. If the object was not constructed from locale data,
851 * both arguments should be set to null. Otherwise, neither
852 * should be null. The actual locale must be at the same level or
853 * less specific than the valid locale. This method is intended
854 * for use by factories or other entities that create objects of
856 * @param valid the most specific locale containing any resource
858 * @param actual the locale containing data used to construct this
860 * @see com.ibm.icu.util.ULocale
861 * @see com.ibm.icu.util.ULocale#VALID_LOCALE
862 * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
864 final void setLocale(ULocale valid, ULocale actual) {
865 // Change the following to an assertion later
866 if ((valid == null) != (actual == null)) {
868 throw new IllegalArgumentException();
871 // Another check we could do is that the actual locale is at
872 // the same level or less specific than the valid locale.
873 this.validLocale = valid;
874 this.actualLocale = actual;
878 * The most specific locale containing any resource data, or null.
879 * @see com.ibm.icu.util.ULocale
881 private ULocale validLocale;
884 * The locale containing data used to construct this object, or
886 * @see com.ibm.icu.util.ULocale
888 private ULocale actualLocale;
890 // -------- END ULocale boilerplate --------