gt:                 for(Object key : keys) {
context: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.commons.lang3.time;
  
  import java.text.DateFormat;
  import java.text.Format;
  import java.text.SimpleDateFormat;
  import java.util.Arrays;
  import java.util.Locale;
  import java.util.TimeZone;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
  
  /**
   * <p>FormatCache is a cache and factory for {@link Format}s.</p>
   * 
   * @since 3.0
   * @version $Id: FormatCache 892161 2009-12-18 07:21:10Z  $
   */
  // TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach.
  abstract class FormatCache<F extends Format> {
      /**
       * No date or no time.  Used in same parameters as DateFormat.SHORT or DateFormat.LONG
       */
      static final int NONE= -1;
      
      private final ConcurrentMap<MultipartKey, F> cInstanceCache 
          = new ConcurrentHashMap<MultipartKey, F>(7);
      
      private static final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache 
          = new ConcurrentHashMap<MultipartKey, String>(7);
  
      /**
       * <p>Gets a formatter instance using the default pattern in the
       * default timezone and locale.</p>
       * 
       * @return a date/time formatter
       */
      public F getInstance() {
          return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault());
      }
  
      /**
       * <p>Gets a formatter instance using the specified pattern, time zone
       * and locale.</p>
       * 
       * @param pattern  {@link java.text.SimpleDateFormat} compatible
       *  pattern
       * @param timeZone  the non-null time zone
       * @param locale  the non-null locale
       * @return a pattern based date/time formatter
       * @throws IllegalArgumentException if pattern is invalid
       *  or <code>null</code>
       */
      public F getInstance(String pattern, TimeZone timeZone, Locale locale) {
          if (pattern == null) {
              throw new NullPointerException("pattern must not be null");
          }
          if (timeZone == null) {
              timeZone = TimeZone.getDefault();
          }
          if (locale == null) {
              locale = Locale.getDefault();
          }
          MultipartKey key = new MultipartKey(pattern, timeZone, locale);
          F format = cInstanceCache.get(key);
          if (format == null) {           
              format = createInstance(pattern, timeZone, locale);
              F previousValue= cInstanceCache.putIfAbsent(key, format);
              if (previousValue != null) {
                  // another thread snuck in and did the same work
                  // we should return the instance that is in ConcurrentMap
                  format= previousValue;              
              }
          }
          return format;
      }
      
      /**
       * <p>Create a format instance using the specified pattern, time zone
       * and locale.</p>
       * 
       * @param pattern  {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
       * @param timeZone  time zone, this will not be null.
       * @param locale  locale, this will not be null.
       * @return a pattern based date/time formatter
       * @throws IllegalArgumentException if pattern is invalid
       *  or <code>null</code>
       */
      abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale);
          
      /**
       * <p>Gets a date/time formatter instance using the specified style,
       * time zone and locale.</p>
       * 
       * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT
       * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT
       * @param timeZone  optional time zone, overrides time zone of
       *  formatted date
       * @param locale  optional locale, overrides system locale
       * @return a localized standard date/time formatter
       * @throws IllegalArgumentException if the Locale has no date/time
       *  pattern defined
       */
      public F getDateTimeInstance(Integer dateStyle, Integer timeStyle, TimeZone timeZone, Locale locale) {
          if (locale == null) {
              locale = Locale.getDefault();
          }
          String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
          return getInstance(pattern, timeZone, locale);
      }
  
      /**
       * <p>Gets a date/time format for the specified styles and locale.</p>
       * 
       * @param dateStyle  date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
       * @param timeStyle  time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
       * @param locale  The non-null locale of the desired format
       * @return a localized standard date/time format
       * @throws IllegalArgumentException if the Locale has no date/time pattern defined
       */
      public static String getPatternForStyle(Integer dateStyle, Integer timeStyle, Locale locale) {
          MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale);
  
          String pattern = cDateTimeInstanceCache.get(key);
          if (pattern == null) {
              try {
                  DateFormat formatter;
                  if (dateStyle == null) {
                      formatter = DateFormat.getTimeInstance(timeStyle, locale);                    
                  }
                  else if (timeStyle == null) {
                      formatter = DateFormat.getDateInstance(dateStyle, locale);                    
                  }
                  else {
                      formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
                  }
                  pattern = ((SimpleDateFormat)formatter).toPattern();
                  String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
                  if (previous != null) {
                      // even though it doesn't matter if another thread put the pattern
                      // it's still good practice to return the String instance that is
                      // actually in the ConcurrentMap
                      pattern= previous;
                  }
              } catch (ClassCastException ex) {
                  throw new IllegalArgumentException("No date time pattern for locale: " + locale);
              }
          }
          return pattern;
      }
  
      // ----------------------------------------------------------------------
      /**
       * <p>Helper class to hold multi-part Map keys</p>
       */
      private static class MultipartKey {
          private final Object[] keys;
          private int hashCode;
  
          /**
           * Constructs an instance of <code>MultipartKey</code> to hold the specified objects.
           * @param keys the set of objects that make up the key.  Each key may be null.
           */
          public MultipartKey(Object... keys) {
              this.keys = keys;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean equals(Object obj) {
              // Eliminate the usual boilerplate because
              // this inner static class is only used in a generic ConcurrentHashMap
              // which will not compare against other Object types
              return Arrays.equals(keys, ((MultipartKey)obj).keys);
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int hashCode() {
              if(hashCode==0) {
                  int rc= 0;
  