Скрытые возможности Java


295

После прочтения скрытых возможностей C # я задумался: каковы некоторые скрытые возможности Java?


17
Обратите внимание, что не всегда хорошая идея использовать эти скрытые функции; часто они удивляют и запутывают других, читающих ваш код.
Кевин Бурриллион

1
Вы (/ кто-то) должны, вероятно, аккуратно суммировать ответы в теле вопроса, как вопрос C #.
ripper234

Ответы:


432

Инициализация двойной скобки застала меня врасплох несколько месяцев назад, когда я впервые обнаружил это, никогда не слышал об этом раньше.

ThreadLocals обычно не так широко известны как способ хранения состояния для каждого потока.

Поскольку в Java JDK 1.5 реализованы чрезвычайно надежные и надежные инструменты параллелизма, помимо просто блокировок, они живут в java.util.concurrent, и особенно интересным примером является подпакет java.util.concurrent.atomic, который содержит потокобезопасные примитивы, которые реализуют сравнение -and-swap операция и может отображаться на реальные версии этих операций с аппаратной поддержкой.


40
Инициализация в двойных скобках ... странно ... Я бы с осторожностью воспринял эту конкретную идиому слишком широко, поскольку она фактически создает анонимный подкласс объекта, что может привести к путанице в задачах equals / hashcode. java.util.concurrent - действительно отличный пакет.
МБ.

6
Я преподавал Java, и это первый раз, когда я сталкиваюсь с этим синтаксисом ... который показывает, что вы никогда не прекращаете учиться = 8-)
Yuval

49
Обратите внимание, что если вы сохраняете ссылку на коллекцию, инициализированную с помощью этой идиомы «двойная скобка» (или если мы называем ее его реальным именем - анонимный класс с блоком инициализатора), вы неявно удерживаете ссылку на внешний объект, который может вызвать неприятную память утечки. Я бы рекомендовал избегать этого вообще.
Ддимитров

51
«Двойная инициализация» - это очень эвфемистическое имя для создания анонимного внутреннего класса, приукрашивания того, что на самом деле происходит, и его звучания, как если бы внутренние классы предназначались для использования таким образом. Это шаблон, который я предпочел бы оставаться скрытым.
Эриксон

11
Практически это не статический блок, а «блок инициализатора», который отличается, поскольку он выполняется в другое время (более подробную информацию см. По ссылке, которую я вставил в ответ)
Борис Терзич,

279

Совместное объединение в дисперсии параметров типа:

public class Baz<T extends Foo & Bar> {}

Например, если вы хотите взять параметр, который является одновременно Comparable и Collection:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

Этот придуманный метод возвращает true, если две заданные коллекции равны или если одна из них содержит данный элемент, в противном случае - false. Следует отметить, что вы можете вызывать методы как Comparable, так и Collection для аргументов b1 и b2.


Мое любимое использование для этого, когда вам нужен метод, который принимает добавляемую последовательность символов.
Нил Коффи

5
Возможно ли иметь «ИЛИ» вместо &?
mainstringargs

9
@Grasper: Нет, OR (непересекающееся объединение) в этом контексте не предусмотрено. Но вместо этого вы можете использовать непересекающийся тип объединения, например Either <A, B>. Этот тип является двойным для типа Pair <A, B>. Посмотрите на функциональную библиотеку Java или базовые библиотеки Scala для примера такого типа данных.
Apocalisp

5
Вы должны сказать, что вы ДОЛЖНЫ расширять только один класс и несколько интерфейсов -> открытый класс Baz <T расширяет Clazz & Interface1 & InterfaceI ... а не класс Baz <T расширяет Clazz1 & ClazzI>
JohnJohnGa

220

Я был удивлен инициализаторами экземпляра на днях. Я удалил некоторые методы, свернутые в коде, и в итоге создал несколько инициализаторов экземпляров:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

Выполнение mainметода покажет:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

Я думаю, это было бы полезно, если бы у вас было несколько конструкторов и вам нужен общий код

Они также предоставляют синтаксический сахар для инициализации ваших классов:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

38
Преимущество этого перед явным методом, который должен быть вызван, состоит в том, что если кто-то позже добавляет конструктор, ему не нужно помнить, чтобы вызывать init (); это будет сделано автоматически. Это может предотвратить ошибки будущих программистов.
Мистер Блестящий и Новый 宇 宇

40
Также, в отличие от метода init (), он может инициализировать конечные поля.
Даррон

2
Что если вы расширите класс и создадите экземпляры для разных детей? Будет ли он вести себя так же?
Кеззер

12
Люди часто раздают сертификаты (например, stackoverflow.com/questions/281100/281127#281127 ) и особенно ставят под сомнение их технические достоинства. Но если бы здесь училось больше программистов для своего SCJP, это не было бы для многих «скрытой возможностью». ;-)
Jonik

12
Бьюсь об заклад, даже книга "Ява в течение 24 часов" имеет эту "очевидную особенность". читать дальше, ребята
:)

201

JDK 1.6_07 + содержит приложение под названием VisualVM (bin / jvisualvm.exe), которое представляет собой приятный графический интерфейс поверх многих инструментов. Это кажется более полным, чем JConsole.


И у него есть плагин (это вещь NetBeans), который позволяет ему использовать плагины Jconsole. Довольно мило.
Турбьёрн Равн Андерсен

VisualVM - лучшая вещь из нарезанного хлеба, правда! Жаль, что он не обладает всеми функциями при работе с JDK 1.5
sandos

Я нахожу VisualVM медленным или непригодным в некоторых обстоятельствах. Коммерческий YourKit не имеет этой проблемы, но, к сожалению, не является бесплатным.
Roalt

Более поздние версии Visual VM, начиная с JDK 1.6.0_22 и более поздних, значительно улучшены. Держу пари, что JDK1.7 имеет еще лучшую версию.
Джангофан


156

Для большинства людей, у которых я беру интервью на должности разработчиков Java, маркированные блоки очень удивляют. Вот пример:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

Кто сказал, что gotoв Java это просто ключевое слово? :)


2
Что ж, я бы предпочел иметь возможность сделать это несколькими способами. Например, я видел людей, использующих System.exit (1); в коде сервлетов и EJB, но это не значит, что мы должны удалить System.exit (); от JDK, верно?
Георгий Болюба

31
При некоторых обстоятельствах в рамках конструкции вложенного цикла может быть полезно перейти к следующей итерации внешнего цикла. Это было бы разумным использованием этой функции.
alasdairg

75
Что особенно неизвестно многим программистам (и, вероятно, точно так же), так это то, что вы можете на самом деле помечать и выделять ЛЮБОЙ старый блок. Это не обязательно должен быть цикл - вы можете просто определить какой-то произвольный блок, присвоить ему метку и использовать разрыв с ним.
Нил Коффи

27
Это вообще не goto, оно может вернуться только к предыдущей итерации (т.е. вы не можете прыгнуть вперед). Это тот же механизм, который возникает, когда итерация возвращает false. Говорить о том, что в java есть goto, все равно, что говорить, что любой язык, чей компилятор создает инструкцию JUMP, имеет оператор goto.
Зомби

4
Таким образом, вы проводите собеседование, основываясь на мелочах Java, а не на способности решать проблемы и продумывать дизайн. Я позабочусь, чтобы я никогда не брал интервью у вашей компании. :)
Джавид Джамаэ

144

Как насчет ковариантных типов возвращаемых данных, которые существуют с JDK 1.5? Это довольно плохо публикуется, так как это несексуальное дополнение, но, насколько я понимаю, абсолютно необходимо для работы дженериков.

По сути, компилятор теперь позволяет подклассу сузить тип возвращаемого значения переопределенного метода, чтобы он был подклассом возвращаемого типа исходного метода. Так что это разрешено:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

Вы можете вызвать метод подкласса valuesи получить отсортированный поток, безопасный Setдля Strings, без необходимости приведения к типу ConcurrentSkipListSet.


Можете ли вы привести пример использования?
Аллен Лалонд

24
Я использую это много. clone () отличный пример. Он должен возвращать Object, что означает, что вы должны сказать, например, (List) list.clone (). Однако если вы объявите как List clone () {...}, то приведение не требуется.
Джейсон Коэн

142

Передача контроля в блоке finally исключает любые исключения. Следующий код не генерирует RuntimeException - он теряется.

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

От http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


7
Это неприятно, но это также своего рода логическое следствие того, как, наконец, работает. Управление потоком try / catch / finally делает то, что предназначено, но только в определенных пределах. Точно так же вы должны быть осторожны, чтобы не вызвать исключение внутри блока catch / finally, или вы также выбросите исходное исключение. И если вы выполните System.exit () внутри блока try, блок finally не будет вызван. Если вы нарушаете нормальный поток, вы нарушаете нормальный поток ...
Нил Коффи

Не используйте наконец {return; } но, наконец, {код без возврата}. Это логично, поскольку, наконец, также предполагается выполнение при возникновении исключений, и единственным возможным значением возврата в качестве обработчика исключений должно быть игнорирование исключения и - действительно - возврат.
Extraneon

21
Это больше похоже на «уловку», чем на скрытую функцию, хотя есть способы, которыми ее можно использовать как единое целое, использование этого метода не будет хорошей идеей.
davenpcj

Eclipse выдает предупреждение, если вы делаете это. Я с Затмением. Если вы хотите поймать исключение ... тогда поймайте исключение.
Гелиос

Это то, что вы платите за грязный код, который возвращается из середины метода. Но все равно хороший пример.
Ростислав Матл

141

Никто не упомянул, что instanceof реализован таким образом, что проверка на нулевое значение не требуется.

Вместо того:

if( null != aObject && aObject instanceof String )
{
    ...
}

просто используйте:

if( aObject instanceof String )
{
    ...
}

9
Обидно, что это такая малоизвестная особенность. Я видел много кода, похожего на первый блок кода.
Питер Долберг

4
Это потому, что в Java есть специальный (скрытый) нулевой тип, который вы не видите и на который не можете ссылаться.
Ник Христов

Что еще хуже, проверка на нуль перед freeзагрузкой или deleteзагрузкой в ​​C / C ++. Такая фундаментальная концепция.
Томас Эдинг

134

Разрешение методов и конструкторов в перечислениях удивило меня. Например:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

Вы даже можете иметь «постоянное тело определенного класса», которое позволяет определенному значению перечисления переопределять методы.

Больше документации здесь .


20
Действительно потрясающая функция - делает перечисления OO и решает многие проблемы инициализации очень чистым способом.
Билл К

5
Enum как синглтон? Перечислить только одно значение?
Георгий Болюба

6
Георгий: Синглтон - это один экземпляр объекта, а не объект с одним значением.
dshaw

20
@ Георгий: см. Также пункт 3 «Эффективной Явы» Джошуа Блоха (2-е изд); «Хотя этот подход еще не получил широкого распространения, одноэлементный тип enum является лучшим способом реализации синглтона».
Джоник

3
Незначительный придурок: mAgeдолжен быть окончательным. В перечислениях редко встречается причина нефинальных полей.
Иоахим Зауэр

121

Типовые параметры для универсальных методов могут быть указаны явно так:

Collections.<String,Integer>emptyMap()

10
И, черт возьми, это безобразно и запутанно. И не имеет отношения к типу безопасности.
Крис Бродфут

8
Мне это нравится. Это делает ваш код немного более явным и, как таковой, более понятным для бедняги, которому придется поддерживать его через год или два.
extraneon

6
На самом деле это очень полезно в ситуациях, когда вы объявили статический универсальный метод, такой как public static <T> T foo(T t). Затем вы можете позвонитьClass.<Type>foo(t);
Finbarr

По некоторым причинам это не работает со статически импортированными методами. Интересно, почему.
Оксайт

Это особенно полезно при использовании троичных if с возвратом. Например return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList(). Это также полезно для некоторых вызовов методов, где простой Collections.emptyMap () может привести к ошибке компиляции.
Андреас Холстенсон

112

Вы можете использовать перечисления для реализации интерфейса.

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

РЕДАКТИРОВАТЬ: Годы спустя ....

Я использую эту функцию здесь

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java

Используя интерфейс, разработчики могут определять свои собственные стратегии. Используяenum средства, я могу определить коллекцию (из пяти) встроенных.


27
Это безумие. (+1)
Головоногий

12
@ Ариан, это не безумие. ЭТОТ. ЯВЛЯЕТСЯ. JAVAAAAAAHHHH!
Slezica

1
Черт возьми, я с Адрианом. Это не Java. Это безумие. Я хочу использовать это.
Slezica

104

Начиная с Java 1.5, Java теперь имеет гораздо более чистый синтаксис для написания функций переменной арности. Таким образом, вместо того, чтобы просто передать массив, теперь вы можете сделать следующее

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

бары автоматически преобразуются в массив указанного типа. Не огромная победа, но, тем не менее, победа.


23
Важно отметить, что при вызове метода вы можете написать: foo («первый», «второй», «третий»)
Стив Армстронг,

9
так что старый привет мир может быть переписан; public static void main (String ... args) {System.out.println ("Привет, мир!"); }
Karussell

@Karussell Возможно, но казалось бы, аргументы не имеют значения: p
Келли Элтон

93

Мое любимое: сбросить все трассировки стека потоков в стандартный вывод.

Windows: CTRL- Breakв вашем окне Java CMD / консоли

UNIX: kill -3 PID


15
Также Ctrl- \ в Unix. Или используйте jstack из JDK.
Том Хотин - tackline

9
Спасибо, вы только что научили меня, что у моей клавиатуры есть Breakклавиша.
Эми Б

2
В Windows CTRL-BREAK работает, только если у вас запущен процесс в текущем окне консоли. Вместо этого вы можете использовать JAVA_HOME / bin / jstack.exe. Просто предоставьте его с идентификатором процесса Windows.
Джавид Джамае

Я думал, что это убить -SIGQUIT
Ник Христов

@ Ник, да, SIGQUIT - это обычно сигнал № 3.
Крис Маццола

89

Несколько человек написали об инициализаторах экземпляров, вот хорошее применение для этого:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

Это быстрый способ инициализации карт, если вы просто делаете что-то быстрое и простое.

Или используя его для создания прототипа рамы быстрого качания:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

Конечно, этим можно злоупотреблять:

    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

Каким-то образом, это немного похоже на то, как если бы ключевое слово «с» (фактически, функциональность) было добавлено в Java. Может быть очень удобно, недавно я проворчал, потому что инициализация массивов не была доступна для Коллекций. Спасибо!
PhiLho

15
Есть один побочный эффект от использования этого, хотя. Создаются анонимные объекты, что не всегда хорошо.
Амит

17
Хотя, посмотрев на это больше, я должен сказать, что меня странно привлекает естественное вложение, которое это обеспечивает, даже версия "Abused".
Билл К

4
Да, мне очень нравится «оскорбленная» версия, я думаю, что она действительно очень четкая и читаемая, но, возможно, это только я.
Барриед

3
Абсолютно согласен, иерархия кода, отражающая иерархию графического интерфейса, является огромным улучшением по сравнению с последовательностью вызовов методов.
opsb

88

Динамические прокси (добавлены в 1.3) позволяют вам определять новый тип во время выполнения, который соответствует интерфейсу. Это пригодилось удивительное количество раз.


10
Динамические прокси - отличная причина, чтобы выбрать написать интерфейс Foo и использовать его везде с классом «FooImpl» по умолчанию. Поначалу это может показаться уродливым («Почему бы просто не иметь класс с именем Foo?»), Но преимущества с точки зрения будущей гибкости и способности к моделированию для юнит-тестов удобны. Хотя есть способы сделать это и для неинтерфейсов, они обычно требуют дополнительных вещей, таких как cblib.
Дариен

82

окончательная инициализация может быть отложена.

Это гарантирует, что даже при сложном потоке логики возвращаемые значения всегда устанавливаются. Слишком легко пропустить случай и вернуть ноль случайно. Это не делает возврат нуля невозможным, просто очевидно, что это специально:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

Это удивительно. Можно ли честно сказать: «Значение конечной переменной можно установить один раз», независимо от того, где оно происходит?
Дэвид Коэль

29
Да, но более строго: «Значение окончательной переменной должно быть установлено один раз»
Аллен Лалонд

6
+1 Согласитесь, это еще один ценный инструмент для выявления ошибок во время компиляции, и программисты, похоже, по какой-то причине его стесняются использовать. Обратите внимание, что, начиная с Java 5, «final» также имеет последствия для безопасности потоков, поэтому возможность установки конечной переменной во время конструктора неоценима.
Нил Коффи

4
Хотя для этого конкретного метода я бы просто использовал несколько возвратов. Фактически, в большинстве случаев, когда это применимо, я бы, вероятно, реорганизовал бы его в отдельный метод и использовал бы несколько возвратов.
ripper234

Мне это нравится! Я всегда удаляла последнее ключевое слово, потому что думала, что оно потерпит неудачу. Спасибо!
КАРАЗИ Иштван

62

Я думаю, что еще одна «упущенная из виду» особенность Java - сама JVM. Это, вероятно, лучшая доступная виртуальная машина. И он поддерживает множество интересных и полезных языков (Jython, JRuby, Scala, Groovy). Все эти языки могут легко и без проблем сотрудничать.

Если вы разрабатываете новый язык (как в случае с scala), вы сразу же получаете все имеющиеся библиотеки, и поэтому ваш язык «полезен» с самого начала.

Все эти языки используют оптимизацию HotSpot. ВМ очень хорошо контролирует и отлаживается.


18
На самом деле это не очень хорошая виртуальная машина. Он был разработан исключительно для запуска JAVA. Типичные динамические и функциональные языки плохо работают с ним. Если вы хотите использовать виртуальную машину, вы должны использовать .NET / Mono. Это было разработано для работы с КАЖДЫМ языком ...
Hades32

14
На самом деле JVM предназначена исключительно для запуска байт-кодов Java. Вы можете компилировать большинство современных языков в байт-код Java. Единственным недостатком Java Bytecode является поддержка динамического языка, указателей и хвостовой рекурсии.
mcjabberz

12
@ Hades32: на самом деле .NET VM очень похожа на JVM. Он только недавно получил поддержку динамических языков (с DLR), и Java 7 также собирается получить эту поддержку. И классический «КАЖДЫЙ язык» .NET (C #, Visual Basic .NET, ...) все имеют практически одинаковый набор функций.
Иоахим Зауэр

13
JVM не поддерживает дженерики, в то время как .NET VM поддерживает. JVM далеко не самый лучший.
Blindy

3
Не стоит сбрасывать со счетов жалобы на специфические языковые функции, которые не поддерживаются непосредственно JVM ... но я склонен думать, что стабильность, кросс-платформенная согласованность и хорошая производительность намного превосходят причины, по которым JVM получает дополнительные баллы. Я уже много лет работаю с серверной Java на многих платформах (включая AS / 400) и смог полностью забыть об этом - ошибки почти всегда есть в коде, который я могу исправить, и это просто не падает
Роб Уилан

58

Вы можете определить анонимный подкласс и напрямую вызвать метод для него, даже если он не реализует интерфейсы.

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

@Vuntic - он позволяет вам определить простой класс в контексте, в котором он необходим.
ChaosPandion

1
@ Chaos, а почему? Есть реальный пример, где это полезно?
Торбьерн Равн Андерсен

10
@Wouter - В этом случае метод, который вызывается для анонимного объекта ( start()), фактически не определен в подклассе ...
Аксель

На самом деле, это очень полезная функция, если вы расширяете базовый класс, который выполняет некоторую необходимую настройку, вызывает метод, который вы пишете, а затем делаете разбор. Начните с этого, вызвав метод в базовом классе (который я, вероятно, не назвал бы тем же именем). Есть пример использования (не определение) здесь
AmigoNico

56

asList в java.util.Arraysпозволяет получить хорошую комбинацию varargs, универсальных методов и автобокса:

List<Integer> ints = Arrays.asList(1,2,3);

15
вы хотите обернуть возвращенный список конструктором List, иначе int будет иметь фиксированный размер (так как он поддерживается массивом)
KitsuneYMG

2
Arrays.asListИмеет необычную особенность , что вы можете set()элементы , но не add()или remove(). Поэтому я обычно оборачиваю его в a new ArrayList(...)или в a Collections.unmodifiableList(...), в зависимости от того, хочу ли я изменить список или нет.
Кристиан Семрау

53

Использование этого ключевого слова для доступа к полям / методам, содержащим класс из внутреннего класса. В следующем, довольно надуманном примере мы хотим использовать поле sortAscending класса контейнера из анонимного внутреннего класса. Использование ContainerClass.this.sortAscending вместо this.sortAscending делает свое дело.

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
Это необходимо, только если вы скрыли имя (в вашем случае, с именем параметра метода). Если бы вы назвали аргумент как-нибудь еще, вы могли бы напрямую получить доступ к переменной члена sortAscending класса Container, не используя 'this'.
ск.

7
Еще полезно иметь ссылку на включающий класс, например. если вам нужно передать его какому-либо методу или разработчику.
PhiLho

Часто используется при разработке макетов Android, чтобы получить контекст, скажем, от слушателя кнопки, с помощью MyActivity.this.
Espinchi

52

Не совсем особенность, но забавный трюк, который я недавно обнаружил на какой-то веб-странице:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

является допустимой программой Java (хотя она генерирует предупреждение). Если вы не понимаете почему, посмотрите ответ Грегори! ;-) Ну, подсветка синтаксиса здесь тоже подсказывает!


15
аккуратно, этикетка с комментарием :)
Thorbjørn Ravn Andersen

46

Это не совсем «скрытые функции» и не очень полезные, но в некоторых случаях может быть чрезвычайно интересным:
класс sun.misc.Unsafe - позволит вам реализовать прямое управление памятью в Java (вы даже можете написать самоизменяющийся код Java с это если сильно постараться)

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
это API Sun. *, который на самом деле не является частью языка Java
DW.

В Unsafe есть ряд других любопытных методов, таких как создание объекта без вызова конструктора, методы malloc / realloc / free style.
Питер Лори

Особенно мне нравятся примитивные геттеры и сеттеры в местах памяти, такие как putDouble (long address, double d).
Даниэль

42

При работе в Swing мне нравится скрытый Ctrl- Shift-F1 функция.

Он сбрасывает дерево компонентов текущего окна.
(Предполагая, что вы не связали это нажатие клавиши с чем-то другим.)


1
Скорее всего, ваш оконный менеджер имеет что-то связанное с этим ключом. Gnome не привязывается к нему, поэтому я предполагаю, что вы используете KDE, который связывает его с «переключением на рабочий стол 13». Вы можете изменить его, перейдя в Панель управления, Региональные, Сочетания клавиш и удалив сопоставление для Shift-Ctrl-F1
Devon_C_Miller

40

Каждый файл класса начинается с шестнадцатеричного значения 0xCAFEBABE чтобы идентифицировать его как действительный байт-код JVM.

( Объяснение )


38

Я голосую за java.util.concurrent с его параллельными коллекциями и гибкими исполнителями, позволяющими среди прочих пулов потоков, запланированных и скоординированных задач. DelayQueue - мой личный фаворит, где элементы становятся доступными после указанной задержки.

java.util.Timer и TimerTask можно смело положить на отдых.

Кроме того, не совсем скрыто, но в другой упаковке, чем другие классы, связанные с датой и временем. java.util.concurrent.TimeUnit полезен при преобразовании между наносекундами, микросекундами, миллисекундами и секундами.

Он читается намного лучше, чем обычный someValue * 1000 или someValue / 1000.


Недавно обнаружен CountDownLatchи CyclicBarrier- так полезен!
Рафаэль

37

Ключевое слово assert на уровне языка .


19
Проблема с утверждением заключается в том, что он должен быть включен во время выполнения.
Extraneon

10
Но если он отключен, значит, его там нет. Вы можете добавить в код столько утверждений, сколько захотите, и у вас не будет никакого снижения производительности, если они отключены.
Рави Валлау

5
Я считаю, что это хорошая вещь об утверждении: его можно отключить без штрафа.
andref

проблема в том, что если вы случайно внедрили побочный эффект в утверждении, вы должны включить утверждение, чтобы ваша программа работала ...
Chii

Чтобы определить, включены ли подтверждения, вы можете использовать {boolean assertsOn = false; assert assertsOn = true; if (assertsOn) {/ * комплексная проверка * /}}. Это также позволяет регистрировать или выдавать исключение, если состояние assert не ожидается.
Фернаколо

37

Не совсем часть языка Java, но дизассемблер javap, поставляемый с Sun JDK, широко не известен и не используется.


36

Добавление конструкции для каждого цикла в 1.5. Я <3 это.

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

И может использоваться во вложенных экземплярах:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

Конструкция for-each также применима к массивам, где она скрывает переменную индекса, а не итератор. Следующий метод возвращает сумму значений в массиве int:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

Ссылка на документацию Sun


30
Я думаю, что использование iздесь очень запутанно, так как большинство людей ожидают, что я буду индексом, а не элементом массива.
cdmckay

Итак ... int sum (int [] array) {int result = 0; for (int element: array) {result + = element; } вернуть результат; }
Дрю

28
Единственное, что сводит меня с ума - это то, что было бы действительно очень легко создать ключевое слово для доступа к значению счетчика циклов, но вы не можете. Если я хочу зациклить два массива и внести изменения в секунду на основе значений в первом, я вынужден использовать старый синтаксис, поскольку у меня нет смещения во втором массиве.
Джерико

6
Жаль, что он не работает и с перечислениями, как те, что используются в JNDI. Это вернулось к итераторам там.
Extraneon

3
@extraneon: взгляните на Collections.list (перечисление <T> e). Это должно помочь с повторяющимися перечислениями в цикле foreach.
Вернер Леманн

34

лично я обнаружил java.lang.Voidочень поздно - улучшает читаемость кода в сочетании с обобщениями, напримерCallable<Void>


2
не совсем. в какой-то момент вам нужно быть конкретным: Executors.newSingleThreadExecutor (). submit (new Callable <Void> () {..}) - вы не можете создать новый Callable <?> (), вам нужно указать явный тип - таким образом, это альтернатива Callable <Object>.
Рахель Люти

4
Void более специфичен, чем Object, поскольку Void может быть только нулем, Object может быть чем угодно.
Питер Лори
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.