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

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

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

Kevin Bourrillion 05.11.2009 21:10

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

ripper234 10.12.2009 22:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
295
2
216 406
100

Ответы 100

Ключевое слово утверждать на уровне языка.

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

extraneon 21.05.2009 19:42

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

Ravi Wallau 09.08.2009 09:15

Я считаю, что это хороший вещь об assert: его можно отключить без штрафных санкций.

andref 11.07.2010 21:41

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

Chii 12.10.2010 15:15

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

fernacolo 23.06.2011 22:26

Мне очень нравится переписанный Threading API из Java 1.6. Звонки отличные. По сути, это потоки с возвращаемым значением.

По сравнению со старыми вещами все просто

Allain Lalonde 12.09.2008 19:59

В основном есть ExecutorServices, которым вы можете отправлять Callables. Когда вы отправляете Callable в ExecutorService, вы получаете обратно Future, в котором есть блокирующий вызов для получения результата Callable (или вы можете спросить его, есть ли результат, неблокирующий).

Adam Jaskiewicz 07.01.2009 22:14

ExecutorService - это способ запуска Callables (и Runnables). Это может быть один фоновый поток, он может поддерживаться пулом потоков, он может даже запускать задачи последовательно в текущем потоке. Зависит от реализации.

Adam Jaskiewicz 07.01.2009 22:16

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

Adam Jaskiewicz 07.01.2009 22:33

статический импорт для «улучшения» языка, чтобы вы могли делать приятные буквальные вещи безопасными для типов способами:

List<String> ls = List("a", "b", "c");

(также можно делать с картами, массивами, наборами).

http://gleichmann.wordpress.com/2008/01/13/building-your-own-literals-in-java-lists-and-arrays/

Продолжая:

List<Map<String, String>> data = List(Map( o("name", "michael"), o("sex", "male")));

Очень жаль, что такой функциональности нет непосредственно в API коллекций.

Chris Mazzola 07.10.2008 16:36

это не часть языка; автор в ссылке определяет метод «Список» для создания списка

kdgregory 01.01.2009 16:23

Это метод вроде: ... public static СписокСписок (T ... elems) {return Arrays.asList (elems); } Также можно написать: ListmyList = новый ArrayList(Arrays.asList («Один», «Два», «Три»)); // как упоминалось в другом посте

xgMz 22.04.2009 23:27

Разве это не шаблон проектирования Factory? Конечно, очень полезно, особенно с varargs.

extraneon 21.05.2009 19:28

статический импорт java.util.Arrays; Listимена = asList ("Джим", "Джон")

opsb 29.10.2010 13:19

@opsb Также необходимо учитывать, что asList возвращает список фиксированного размера, поддерживаемый массивом.

Jeremy 08.01.2012 19:19

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

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

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

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

Hades32 22.06.2009 21:33

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

mcjabberz 18.09.2009 19:43

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

Joachim Sauer 27.11.2009 11:12

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

Blindy 27.11.2009 11:52

Я бы сказал, что BEAM (для Erlang) - «лучшая» виртуальная машина. По крайней мере, для (большого) подмножества лучших виртуальных машин.

HeMan 15.02.2011 17:29

Хорошо, может быть, не самый лучший для большинства определений слова «лучший». Тем не менее я считаю это особенностью java. У него приличный JIT (Hotspot), есть много реализаций, он работает на самых разных системах ...

Mo. 19.02.2011 18:24

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

Rob Whelan 09.01.2012 00:22

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

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

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

Жаль, что моя IDE (NetBeans) ужасно их форматирует при автоматическом форматировании.

Allain Lalonde 12.09.2008 19:57

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

MB. 17.09.2008 16:02

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

Yuval 23.09.2008 12:48

Обратите внимание, что компилятор генерирует AnonymousInnerClass для реализации инициализации двойной скобки, поэтому он работает только для не финальных классов. Это досадно, поскольку буквальные инициализации часто используются как константы.

Chris Noe 23.09.2008 16:48

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

ddimitrov 05.10.2008 17:05

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

erickson 23.10.2008 18:27

Должен признать, что впервые вижу двойные фигурные скобки в Java. Отличный совет !!!

Stephane Grenier 19.01.2009 18:48

Чтобы убедиться, что я понимаю, двойная скобка создает анонимный внутренний класс, а затем создает внутри него статический блок, который затем позволяет выполнять методы из статического контекста. Правильный?

Drew 11.03.2009 02:20

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

Boris Terzic 11.03.2009 12:49

Это, вероятно, нормально, если использовать его время от времени, но если вы поощряете всех делать это, ваш проект будет завален множеством ложных анонимных классов, прежде чем вы это узнаете. Например, обычно предпочтительнее использовать Arrays.asList () для инициализации хеш-набора.

Neil Coffey 20.04.2009 07:50

Это также известно как «изобретение сумасшедшего боба». Хотя я не могу найти происхождение этого имени, Google находит несколько вариантов использования.

Chadwick 31.05.2009 13:18

Хотя двойная скоба интересна - я бы сказал, что она того не стоит. По крайней мере, вы смешиваете данные с кодом - всегда плохая идея. Чтобы уменьшить размер, их пример будет иметь еще меньшую версию: String initial = new String [] {"XZ13s", "AB21 / X", "YYLEX", "AR2D"}; тогда просто используйте initial в цикле «добавляет». Это имеет дополнительное преимущество, заключающееся в том, что ваши данные извлечены на 95%, и их будет тривиально полностью исключить из вашего кода. Создание строковых массивов - это очень легкий синтаксис, который отлично подходит для того, чтобы ваш код и данные не стали слишком близкими.

Bill K 12.06.2009 01:20

Не нравится, мне немного ужасно создавать анонимный подкласс без всякой причины :)

Chris Dennett 06.03.2010 06:10

«Инициализация двойной скобки» - это на самом деле три отдельных понятия. Они не связаны между собой, за исключением того, что имеют похожий синтаксис, поэтому я не уверен, почему мы изобрели термин, охватывающий все три. Разработчики должны понимать, что это конструкции кода, которые могут использоваться по-разному. Это: объявление анонимного класса: new Object () {}, блок инициализатора: class MyObject {int x; {х = 0; / * блок инициализатора не обязательно должен быть статическим * /}} и обозначение литерала массива: new Object [] {"One", "Two", "Three"}. Я бы не назвал ничего из этого антипаттерном, хотя использование анонимных классов должно быть ограничено.

RMorrisey 15.06.2010 04:12

Я часто использую его для Ожидания JMock. Я не видел в этом другой необходимости.

Wim Deblauwe 07.04.2011 16:36

Я обнаружил, что инициализация двойных скобок очень полезна при создании некоторых сложных объектов JAXB. Например, у меня была задача создать XML-код SID (общая информация / модель данных) с помощью JAXB, и это стало в 10 раз более интуитивно понятным и простым с использованием инициализации с двойными скобками. Вот пример: pastebin.com/29wiyGhj

bezmax 10.06.2011 17:41

На самом деле это не особенность, но меня заставляет посмеяться, что goto - это зарезервированное слово, которое ничего не делает, кроме как побуждает javac ткнуть вас в глаз. Напомню, что вы сейчас находитесь в OO-land.

stackoverflow.com/questions/15496/… :-)
Nivas 27.01.2009 23:56

Есть ли какая-то связь между объектно-ориентированным программированием и отказом от "goto"?

Adrian Pronk 01.02.2010 10:51

Как новичок, я очень ценю программное обеспечение для мониторинга JConsole в Java 6, оно уже решило для меня несколько проблем, и я продолжаю находить для него новые применения.

По-видимому, JConsole уже была в Java 5, но я считаю, что сейчас она улучшена и, по крайней мере, на данный момент работает намного стабильнее.

JConsole в Java 5: JConsole в Java 5

JConsole в Java 6: JConsole в Java 6

И пока вы это делаете, внимательно посмотрите на другие инструменты из этой серии: Инструменты устранения неполадок Java 6

JConsole будет заменена на VisualVM в будущих версиях (возможно, 6u10?)

Tom 27.09.2008 15:10

Конечно, JConsole заменят, вернее доработают, думаю уже с 6u7. Но многие по-прежнему используют старые версии suns JVM и, следовательно, нуждаются в JConsole. Я до сих пор не нашел ничего, подтверждающего теорию о том, что JVisualVM будет поддерживать более старые версии JDK.

PPS 14.10.2008 18:04

Это не совсем скрыто, но отражение невероятно полезно и мощно. Замечательно использовать простой Class.forName ("..."). NewInstance (), где тип класса настраивается. Такую фабричную реализацию легко написать.

Я постоянно использую отражение, чтобы делать такие вещи, как T [] filterItems (T []), который затем можно вызвать с помощью items = filterItems (items); Определение метода немного уродливее, но оно действительно упрощает чтение клиентского кода.

Marcus Downing 17.09.2008 18:12

Это мощно, потому что позволяет нарушить все статические гарантии и инвариантные Java, javac и интерфейсы, которые вам дают. Используйте с особой осторожностью.

Raphael 01.03.2012 14:39

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

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

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

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

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

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

Allain Lalonde 12.09.2008 19:58

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

Jason Cohen 14.09.2008 19:04

Функторы - это круто. Они довольно близки к указателю на функцию, что, как обычно говорят, невозможно в Java.

Функторы в Java

Не невозможно, просто невозможно многословно.

Pete Kirkham 04.02.2009 19:11

Разве это не особенность упс, чем специфическая для java ??

Ravisha 24.08.2010 11:08

Для большинства людей, которых я беру интервью у 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 - это просто ключевое слово? :)

Я почти надеюсь, что люди не знают об этой функции. Намного предпочтительнее, чтобы они организовали свой код в более мелкие, более значимые методы и в большинстве случаев просто использовали return. В настоящий момент существует большой фурор вокруг добавления этой языковой конструкции в PHP6.

Cheekysoft 07.09.2008 19:28

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

Georgy Bolyuba 08.09.2008 14:25

Я согласен с тем, что это должно быть разрешено в языке, даже если оно не используется часто. Я не могу припомнить ни одного случая, когда я его использовал, но я видел обе стороны аргумента в пользу его использования. Лучше иметь его и не использовать, чем нуждаться в нем и не иметь.

martinatime 17.09.2008 00:41

Я нашел один случай, когда это было полезно, сделайте странный поток. В конце концов, я просто переделал все это, чтобы оно не понадобилось, и это было проще. Я решил придерживаться правила «психопат, который знает, где ты живешь».

Bob Gettys 26.09.2008 17:13

Это должен быть блок? У меня создалось впечатление, что он просто помечает цикл for.

Jack Leow 27.10.2008 02:48

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

alasdairg 08.11.2008 21:57

в случае нескольких вложенных циклов, да. Но я бы лучше переписал код.

Georgy Bolyuba 13.11.2008 02:58

Я использовал это в stackoverflow.com/questions/288200/… Первый раз, когда я использовал это, казалось естественным ... :-)

PhiLho 13.12.2008 12:01

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

Neil Coffey 20.04.2009 08:10

Что за сюрприз, я тоже понятия не имел. Я люблю спагетти, но не в коде, я не уверен, что буду использовать опасные знания в будущем

victor hugo 10.05.2009 02:47

Хммм, вперед. Давно не виделись. Вдохновение наполняет ... Затмение, я иду!

extraneon 21.05.2009 19:25

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

Zombies 01.10.2009 17:38

Это отличная функция, которую я использую время от времени, чтобы избежать вложенных состояний if и сократить некоторые итерационные конструкции. Это не goto; просто потому, что вы (люди) не знаете, что это неправильно использовать. Всем «напуганным» стоит почитать какую-нибудь книгу по Java.

Ondra Žižka 23.01.2010 03:22

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

RMorrisey 15.06.2010 04:19

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

Javid Jamae 25.08.2010 00:35

Итак, вы комментируете, расширяя точку зрения и / или делая некоторые далеко идущие обобщения и / или предположения. Я никогда больше не буду читать ваши комментарии. :)

Georgy Bolyuba 25.08.2010 04:43

Это всегда можно сделать без помеченного блока (извините за отсутствие пробелов): boolean breakSet = false; для (int i = 0; i

Paul Jackson 13.10.2011 16:27

@Zombies: «Это вообще не goto, он может только вернуться к предыдущей итерации (то есть: вы не можете перейти вперед)». Какие? Вы вообще код смотрели? Что вы имеете в виду "не может прыгнуть вперед?"

Georgy Bolyuba 13.10.2011 17:38

Я знал, что Java 6 включает поддержку сценариев, но недавно обнаружил рукопись, который может интерпретировать и запускать JavaScript (и, как предполагается, другие языки сценариев, такие как Groovy) в интерактивном режиме, вроде как оболочка Python или irb в Ruby

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

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

Darien 21.04.2010 23:57

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

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);
}

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

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

Neil Coffey 20.04.2009 07:51

Можно ли поставить там «ИЛИ» вместо &?

mainstringargs 16.06.2009 22:37

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

Apocalisp 17.06.2009 01:51

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

JohnJohnGa 17.10.2011 12:53

Я знаю, что это было добавлено в версии 1.5, но новый тип перечисления - отличная функция. Отсутствие необходимости использовать старый «шаблон int enum» очень помогло моему коду. Проверьте JLS 8.9 за сладкую подливку к картофелю!

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

Allain Lalonde 12.09.2008 20:01

final для переменных экземпляра:

Действительно полезно для многопоточного кода и значительно упрощает споры о состоянии и правильности экземпляра. Я нечасто видел это в контексте отрасли и часто не думал о Java-классах.


static {something;}:

Используется для инициализации статических членов (также я предпочитаю для этого статический метод (потому что у него есть имя). Не думал.

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

Graham Edgecombe 05.06.2009 23:00

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

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");
}};

Вероятно, было бы более разборчиво иметь метод, который вызывается всеми вашими конструкторами, или чтобы все конструкторы вызывали корневой this (...), а не super (...)

Allain Lalonde 18.09.2008 16:16

Полезно знать, что проверенные исключения, созданные в анонимных инициализаторах, должны быть объявлены конструкторами. Статические инициализаторы не могут генерировать проверенные исключения.

Tom 27.09.2008 15:09

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

Mr. Shiny and New 安宇 10.10.2008 19:45

Кроме того, в отличие от метода init (), он может инициализировать поля final.

Darron 07.01.2009 21:45

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

Kezzer 27.01.2009 15:48

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

Jonik 21.04.2009 12:46

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

Özgür 06.05.2009 23:40

@Jonik Я учился на своем SCJP и помню, как видел это, но давно забыл об этом. Было приятно увидеть, что это опубликовано в этой ветке ... это не метод, который вы видите, используемый каждый день.

JasonStoltz 24.02.2011 15:40

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

slezica 13.10.2011 16:56

Новый Эффективная Java Джошуа Блоха - хороший ресурс.

Отличная книга, но в ней не так много скрытых функций.

James McMahon 16.10.2008 16:35

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

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

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

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

Дополнительная документация здесь.

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

Bill K 06.10.2008 22:00

Из-за этого перечисления также отлично подходят для синглтонов.

Chii 10.10.2008 15:30

Enum как синглтон? Enum только с одним значением?

Georgy Bolyuba 13.11.2008 03:01

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

dshaw 18.11.2008 01:43

Это действительно удобно, если вам нужны счетчики относительно значения. Итак, в этом примере, возможно, вы могли бы инициализировать Cats с указанным значением возраста, а затем иметь FELIX (2 + age), таким образом, возраст Феликса будет относиться к экземпляру возраста Cats.

Kezzer 27.01.2009 15:52

Перечисления настолько объектно-ориентированные, что вы даже можете добавить общедоступный void setAge (int age) {this.mAge = afe} ... и он работает !!

Olivier 09.04.2009 00:56

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

Jonik 21.04.2009 12:57

Мелкие придирки: mAge должен быть окончательным. Редко есть причина для незавершенных полей в перечислениях.

Joachim Sauer 06.10.2010 12:25

Это почти сводит на нет цель использования перечислений IMO.

Kelly Elton 03.10.2011 02:38

@Jonik, хотя у этого есть преимущества в отношении инициализации экземпляра синглтона и доступа к нему, это мешает вам иметь класс синглтона, расширяющий другой класс (все перечисления неявно расширяют java.lang.enum) и, хотя обычно это не нужно / нежелательно, расширять.

Asaf 13.01.2012 03:29

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

sinuhepop 06.05.2012 23:51

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

Самосвязанные дженерики:

class SelfBounded<T extends SelfBounded<T>> {
}

http://www.artima.com/weblogs/viewpost.jsp?thread=136394

см. также crtp справки: artima.com/weblogs/viewpost.jsp?thread=133275

Ray Tayek 01.01.2009 10:03

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

И у него есть плагин (это штука netbeans), который позволяет использовать плагины Jconsole. Довольно мило.

Thorbjørn Ravn Andersen 26.05.2009 11:54

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

sandos 17.02.2010 15:26

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

Roalt 23.09.2010 15:33

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

djangofan 25.08.2011 00:40

Параметры типа для универсальных методов можно указать явно следующим образом:

Collections.<String,Integer>emptyMap()

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

Chris Broadfoot 16.09.2008 16:21

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

extraneon 21.05.2009 19:30

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

Finbarr 13.05.2010 12:20

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

oksayt 25.04.2011 21:30

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

Andreas Holstenson 01.07.2011 00:30

Им потребовалось достаточно времени, чтобы добавить поддержку для этого,

Системный лоток

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

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

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

KitsuneYMG 04.08.2009 17:39

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

Christian Semrau 04.12.2010 01:31

Некоторые трюки с потоком управления, finally вокруг оператора return:

int getCount() { 
  try { return 1; }
  finally { System.out.println("Bye!"); }
}

Правила для определенное назначение будут проверять, что последняя переменная всегда назначается с помощью простого анализа потока управления:

final int foo;
if (...)
  foo = 1;
else
  throw new Exception();
foo+1;

JVisualVM из каталога bin в дистрибутиве JDK. Мониторинг и даже профилирование любого java-приложения, даже того, которое вы не запускали с какими-либо специальными параметрами. Только в последних версиях Java 6SE JDK.

Если вы используете Spring для настройки ваших аннотированных компонентов JMX для работы с jconsole и jvisualvm, вы необходимость запускаете интерфейс управления вручную вместо того, чтобы полагаться на виртуальную машину, созданную по умолчанию. Если вы этого не сделаете, вы столкнетесь с проблемами из-за наличия нескольких конфликтующих «синглтонов», и ваши JMX-бины аккуратно окажутся в неправильном…

Donal Fellows 11.06.2010 12:49

Передача управления в блоке 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

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

Neil Coffey 20.04.2009 07:54

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

extraneon 21.05.2009 19:21

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

davenpcj 04.06.2009 00:00

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

helios 03.03.2010 18:24

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

Rostislav Matl 22.06.2010 16:21

@ Нил Коффи: Если вы, наконец, вызовете исключение внутри, но поймаете его, я полагаю, что это не проблема?

Bart van Heukelom 05.09.2011 19:23

Добавление конструкции цикла for-each в версии 1.5. я

// 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

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

cdmckay 23.02.2009 10:28

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

Drew 11.03.2009 02:27

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

Jherico 20.05.2009 01:34

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

extraneon 21.05.2009 19:32

@extraneon: взгляните на Collections.list (Enumerationд). Это должно помочь с повторением перечислений в цикле foreach.

Werner Lehmann 25.03.2010 02:49

Единственная возможная проблема с этим состоит в том, что он использует Iterator списка, и любое изменение списка в цикле вызовет ConcurrentModificationException.

Finbarr 13.05.2010 12:26

@deepc К сожалению, это создает копию перечисления, а не представление List, поэтому я создал свой собственный адаптер Iterable, который оборачивается вокруг Enumeration.

Bart van Heukelom 05.09.2011 19:51

«const» - это ключевое слово, но вы не можете его использовать.

int const = 1;   // "not a statement"
const int i = 1; // "illegal start of expression"

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

Не совсем «особенность», но определенно «скрытая».

Michael Myers 18.10.2008 00:13

Не просто не-функция, а анти-функция! (Я также не упомянул, что goto то же самое - зарезервировано, но не реализовано).

Michael Myers 21.07.2009 18:22

Он зарезервирован для компилятора, чтобы создавать более точные сообщения об ошибках.

Paŭlo Ebermann 15.03.2011 01:19

goto - это тоже ключевое слово, которое нельзя использовать. ;)

Peter Lawrey 06.05.2011 11:24

@ Питер Лоури: Я знаю, но это уже было опубликовано.

Michael Myers 06.05.2011 17:07

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

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

    System.exit(0);
  }
}

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

аккуратно, этикетка с комментарием :)

Thorbjørn Ravn Andersen 26.05.2009 11:57

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

windows: CTRL-Break в окне java cmd / консоли

unix: kill -3 PID

Также ctrl- \ в Unix. Или используйте jstack из JDK.

Tom Hawtin - tackline 17.09.2008 18:53

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

Amy B 19.08.2010 02:53

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

Javid Jamae 25.08.2010 00:40

Я думал, что это было убить -SIGQUIT

Nick Hristov 01.07.2011 08:14

@Nick, да, SIGQUIT - это обычно сигнал №3.

Chris Mazzola 14.07.2011 19:32

Полномочия, которые вы можете получить над сборщиком мусора и то, как он управляет сборкой объектов, очень эффективны, особенно для долго работающих и чувствительных ко времени приложений. Он начинается со слабых, мягких и фантомных ссылок в пакете java.lang.ref. Взгляните на них, особенно для создания кешей (уже есть java.util.WeakHashMap). Теперь углубитесь в ReferenceQueue, и вы получите еще больший контроль. Наконец, возьмите документацию по самому сборщику мусора, и вы сможете контролировать, как часто он запускается, размеры различных областей сбора и типы используемых алгоритмов (для Java 5 см. http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html).

WeakHashMap - это нет, подходящий для создания кешей.

Bombe 27.11.2009 17:54

Использование ключевого слова это для доступа к полям / методам содержащего класса из внутреннего класса. В приведенном ниже довольно надуманном примере мы хотим использовать поле 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;
}
}

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

sk. 04.02.2009 20:12

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

PhiLho 14.02.2009 22:13

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

espinchi 29.04.2011 21:19

Это не совсем «скрытые функции» и не очень полезные, но в некоторых случаях могут быть чрезвычайно интересными:
Класс 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);
        }
    };
}

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

DW. 05.03.2009 05:53

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

Peter Lawrey 23.07.2010 01:11

Мне особенно нравятся примитивные методы получения и установки в ячейках памяти, такие как putDouble (длинный адрес, double d).

Daniel 27.02.2011 01:10

Поскольку никто еще не сказал этого (я думаю), моя любимая функция - автоматический бокс!

public class Example
{
    public static void main(String[] Args)
    {
         int a = 5;
         Integer b = a; // Box!
         System.out.println("A : " + a);
         System.out.println("B : " + b);
    }
}

Думаю, речь идет о скрытых функциях, а не о любимых функциях. Я предполагаю, что автобокс довольно хорошо известен всем, кто использует 1.5 или новее.

Andrew Swan 25.09.2008 03:08

@Trick Использование valueOf явно не имеет значения, поскольку автобокс компилируется с вызовом valueOf. Это более эффективно с точки зрения памяти по сравнению с вызовом конструктора Integer или Long для небольших значений, поскольку valueOf использует кеш малых значений.

Christian Semrau 04.12.2010 02:25

автобокс - одна из наиболее часто используемых функций. Не то чтобы это серьезная проблема, на самом деле, вы никогда этого не заметите, но вы найдете тысячи случаев, таких как boolean b = Boolean.valueOf (someString), во всех мыслимых проектах.

MeBigFatGuy 02.04.2011 20:40

Как насчет файлов свойств в выбранной вами кодировке? Раньше при загрузке свойств вы предоставляли InputStream, а метод load() декодировал его как ISO-8859-1. Вы мог на самом деле храните файл в какой-то другой кодировке, но вам пришлось использовать такой отвратительный хак после загрузки, чтобы правильно декодировать данные:

String realProp = new String(prop.getBytes("ISO-8859-1"), "UTF-8");

Но, начиная с JDK 1.6, существует метод load(), который принимает Reader вместо InputStream, что означает, что вы можете использовать правильную кодировку с самого начала (есть также метод store(), который принимает Writer). Мне это кажется большим делом, но, похоже, он был прятан в JDK без всяких помпезностей. Я наткнулся на это только несколько недель назад, и быстрый поиск в Google обнаружил лишь одно случайное упоминание о нем.

Не взламывайте, пожалуйста - это испортит все escape-последовательности \uXXXX. Лучше использовать native2ascii для преобразования файла после редактирования и перед развертыванием или использовать читательский вариант метода load().

Paŭlo Ebermann 15.03.2011 01:21

Если вы много занимаетесь разработкой JavaBean и работаете с поддержкой изменения свойств, вы обычно заканчиваете писать много сеттеров следующим образом:

public void setFoo(Foo aFoo){
  Foo old = this.foo;
  this.foo = aFoo;
  changeSupport.firePropertyChange("foo", old, aFoo);
}

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

public void setFoo(Foo aFoo){
  changeSupport.firePropertyChange("foo", this.foo, this.foo = aFoo);
}

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

Четко ли определен порядок выполнения аргументов в Java? В противном случае это может привести к беспорядку.

Konrad Rudolph 26.09.2008 17:10

Он хорошо определен, но в целом не совсем понятен. Технически это сработает, но явно сбивает с толку.

Heath Borders 26.09.2008 18:40

Да - порядок или выполнение аргументов очень хорошо определено. Я не уверен, что согласен с тем, что это более запутанно, чем наличие трех строк мусорного кода в каждом сеттере в каждом отдельном JavaBean - гораздо лучше сосредоточиться на коде, который вы хотите написать, а не на этом типе шаблона!

Kevin Day 30.09.2008 07:52

Кома порядок выполнения очень четко определен. Всегда должно быть слева направо.

Bill K 06.10.2008 22:08

Я не понимаю, почему более короткую версию легче создать автоматически, чем более длинную.

Jason Orendorff 02.12.2009 19:40

Джейсон, честно говоря, генерация кода может сделать это в любом случае. Я думаю, это своего рода точка генерации кода ;-) Все же намного проще читать код с уменьшенным шаблоном (наличие геттера и сеттера вообще все еще является огромным количеством шаблонов, но это обсуждение в другой день)

Kevin Day 07.12.2009 04:30

Вы можете использовать для этого проект lombok.

Alfred 07.02.2010 02:00

Фабрика строковых параметризованных классов.

Class.forName( className ).newInstance();

Загрузите ресурс (файл свойств, xml, xslt, изображение и т. д.) Из файла jar развертывания.

this.getClass().getClassLoader().getResourceAsStream( ... ) ;

Что меня действительно удивило, так это механизм настраиваемой сериализации.

Хотя это методы частный!!, они являются "таинственно", вызываемыми JVM во время сериализации объекта.

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

Таким образом, вы можете создать свою собственную сериализацию, чтобы сделать ее более «любой» (безопасной, быстрой, редкой, простой и т. д.)

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

Вот статья. http://java.sun.com/developer/technicalArticles/Programming/serialization/

Это также полезно для настраиваемой сериализации для объектов с несериализуемыми членами.

Jorn 03.11.2008 00:36

Вы можете объявить класс в методе:

public Foo foo(String in) {
    class FooFormat extends Format {
        public Object parse(String s, ParsePosition pp) { // parse stuff }
    }
    return (Foo) new FooFormat().parse(in);

}

Вы также могли бы просто перейти на новый Format () {вместо объявления класса FooFormat

Pyrolistical 03.10.2008 23:23

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

TREE 10.11.2008 17:36

и они называются локальными классами :) java.sun.com/docs/books/jls/second_edition/html/…

Özgür 24.05.2009 14:22

Я предпочитаю приручить анонимные классы, заставляя их обращаться к основному объекту для выполнения своей работы; анонимный класс - это просто адаптер, поэтому его легко понять.

Donal Fellows 11.06.2010 12:42

@Donal - я часто использую это с кодом пользовательского интерфейса. Однако стоит сказать, что этот дизайн плох с точки зрения рефакторинга. Вы можете извлечь класс «верхнего уровня» и обнаружить, что его логика полностью реализована другим классом!

oxbow_lakes 12.06.2010 02:34

@oxbow: Я не совсем понимаю вашу точку зрения. Единственное, что есть в моем внутреннем классе, - это вызов (обычно непубличного) метода внешнего класса. Хотя да, теоретически это может быть довольно неожиданным, но на практике это довольно легко увидеть, поскольку это только вызов без обработки исключений.

Donal Fellows 12.06.2010 11:05

API обработки аннотаций из Java 6 выглядит очень перспективным для генерации кода и проверки статического кода.

окончательную инициализацию можно отложить.

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

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;
}

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

David Koelle 04.02.2009 22:12

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

Allain Lalonde 05.02.2009 01:15

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

Neil Coffey 20.04.2009 08:16

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

ripper234 18.11.2009 00:31

Мне это нравится! Я всегда удалял последнее ключевое слово, потому что думал, что оно не сработает. Благодарность!

KARASZI István 25.01.2010 13:20

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

opsb 29.10.2010 13:12

В нескольких комментариях упоминается множественный возврат - обратите внимание, что вы можете получить то же преимущество, что и с последней переменной, если опустите предложение return в конце. Вы можете быть уверены, что все случаи обработаны (и возвращены соответствующие значения), потому что в противном случае он не будет компилироваться.

Rob Whelan 09.01.2012 00:16

Несколько лет назад, когда мне приходилось делать Java (1.4.x), я хотел метод eval (), а Suns javac был (был?) Написан на Java, поэтому нужно было просто связать tools.jar и использовать его с некоторым клеевым кодом вокруг Это.

Обработка Java делает изящный трюк с определением переменных, если вы не используете инициализатор по умолчанию.

{
   int x;

   if (whatever)
      x=1;

   if (x == 1)
      ...
}

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

int x=0;
String s=null;

быть плохим шаблоном, поскольку он блокирует эту полезную проверку.

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

+1 Согласен - по какой-то причине некоторых людей "сбивает с толку" не указывать начальное значение для переменной, как будто они думают, что компилятор тайно собирается выбрать случайное число или что-то в этом роде. Но, как вы правильно сказали, это ценный инструмент для выявления определенных ошибок во время компиляции.

Neil Coffey 20.04.2009 08:13

Это потому, что во вселенной C неинициализированные указатели были проклятием существования - хотя, если я правильно помню, во вселенной C++ указатели автоматически инициализировались нулевым значением, если они размещались в стеке.

Chris K 12.06.2009 01:04

Да, именно поэтому стоит отметить, что это уже не очень хорошая идея и даже несколько контрпродуктивна.

Bill K 12.06.2009 01:13

По возможности используйте final для дополнительных проверок.

Wouter Lievens 01.07.2009 14:22

Вы можете получить доступ к конечным локальным переменным и параметрам в блоках инициализации и методах локальных классов. Учти это:

    final String foo = "42";
    new Thread() {
        public void run() {
             dowhatever(foo);
        }
    }.start();

Немного похоже на закрытие, не так ли?

Я знал, что вы не можете получить доступ к нефиналам, но был удивлен, что вы может получили доступ к финалам.

Hans-Peter Störr 17.12.2008 20:47

Значение:

new URL("http://www.yahoo.com").equals(new URL("http://209.191.93.52"))

это true.

(Из Java Puzzlers)

Только если вы подключены к Интернету. Если он не может разрешить адрес, он вернет false, и поэтому класс URL разрывает контракт equals (). Лучше использовать класс URI в java.net.

Jorn 03.11.2008 00:39

И этого не должно быть, потому что HTTP-сервер может иметь виртуальный хостинг и может вести себя иначе.

rds 27.07.2011 20:25

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

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");
                        }
                     });
                 }});
        }});
    }};

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

PhiLho 13.12.2008 12:06

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

amit 10.02.2009 11:14

Для большого приложения с графическим интерфейсом, разработанного таким образом, вероятно, потребуется немного больше места для перманента. Хотя я не думаю, что нужно много места для хранения чего-то, что по сути является именем класса и инициализатором.

extraneon 21.05.2009 19:39

Должен сказать, что это лучшее использование статических инициализаторов, чем №1, но ничего себе. Неужели это действительно так много преимуществ по сравнению с обозначением рамки "f" и кнопок b? Читаемость, я бы сказал, что даже «короткие» названия лучше, чем это, если бы не только фактор «без сюрпризов».

Bill K 12.06.2009 01:31

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

Bill K 12.06.2009 01:32

Мне тоже нравится :) Это как JavaFX, но бесплатно

Vlagged 22.06.2009 11:29

Ага, мне очень нравится "злоупотребленная" версия, я думаю, что она действительно очень ясна и читабельна, но, возможно, это только я.

barryred 05.08.2010 19:55

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

opsb 29.10.2010 13:08

Мне это не нравится, потому что это позволяет приложению запускаться даже медленнее, чем это делает Java. Он создает новый подкласс HashMap, который совершенно бесполезен.

Daniel 04.07.2011 02:34

"ссылочная прозрачность" - вот причина того, почему такое вложение кажется приятным, см. википедию. его также смутно шепелявые, даже "оскорбленные" версии, шепелявые, кажется, имеют высокую терпимость к глубокой композиции. github.com/technomancy/leiningen/blob/master/src/leiningen/…

Dustin Getz 09.01.2012 02:32

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

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

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

Здесь важно то, что при вызове метода вы можете написать: foo ("first", "second", "third")

Steve Armstrong 25.03.2009 23:03

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

Karussell 23.01.2010 00:56

@Karussell Может быть, но вроде бы аргументы неуместны: p

Kelly Elton 03.10.2011 02:41

Javadoc - при правильном написании (к сожалению, не всегда в случае с некоторыми разработчиками) он дает вам четкое, связное описание того, что должен делать код, в отличие от того, что он делает на самом деле. Затем его можно превратить в удобный для просмотра набор HTML-документации. Если вы используете непрерывную интеграцию и т. д., Ее можно создавать регулярно, чтобы все разработчики могли видеть последние обновления.

SwingWorker для простого управления обратными вызовами пользовательского интерфейса из фоновых потоков.

Экземпляры одного и того же класса могут иметь доступ к закрытым членам других экземпляров:

class Thing {
  private int x;

  public int addThings(Thing t2) {
    return this.x + t2.x;  // Can access t2's private value!
  }
}

Только совсем недавно я узнал об этом, и кто-то должен был указать мне на это в комментарии, оставленном в моем блоге.

moffdub 08.01.2009 03:29

Это удивительно, если у вас есть доступ к объектно-ориентированному языку, отличному от C++.

Pete Kirkham 04.02.2009 19:12

Это ужасно. Не делай этого. Другой человек имеет право заглядывать мне в кишечник не потому, что я человек ;-)

cadrian 30.06.2009 17:33

Но как бы вы сделали правильную реализацию hash / equals, если не можете получить доступ к его внутренностям?

Chii 21.07.2009 16:41

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

TofuBeer 05.07.2010 22:38

По-видимому, с некоторыми отладочными сборками есть опция, которая выгружает собственный (JIT) ассемблерный код из HotSpot: http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html

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

download.java.net/jdk6/binaries and then for whatever platform you use the last link (with debug in the name). I loooooove that feature!
akuhn 17.04.2009 05:05

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

java.util.Timer и TimerTask можно безопасно остановить.

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

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

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

Raphael 01.03.2012 14:06

Ключевое слово strictfp. (Я никогда не видел, чтобы он использовался в реальном приложении :)

Вы можете получить класс для примитивных типов, используя следующую нотацию: int.class, float.class и т. д. Очень полезно при рефлексии.

Конечные массивы могут использоваться для "возврата" значений из анонимных внутренних классов (предупреждение, бесполезный пример ниже):

final boolean[] result = new boolean[1];
SwingUtilities.invokeAndWait(new Runnable() {
  public void run() { result[0] = true; }
});

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

Chii 07.01.2009 18:07

Ромен Гай? Например, в Ромен Гай? ... Во всяком случае, +1 для int.class. Я думал, что Integer.TYPE - единственный способ.

Michael Myers 07.01.2009 21:29

Более чем бесполезно. Код, следующий сразу за этим, скорее всего, будет выполнен до обратного вызова EDT. Следовательно, он не увидит истинной ценности.

Tom Hawtin - tackline 22.06.2009 04:39

Я сам использовал strictfp. Это было для программы, в которой потенциальное перемещение двойной между регистрами (80-битные) и RAM (64-битные) могло вызвать проблемы.

Chinmay Kanchi 17.12.2009 03:35

На самом деле для invokeAndWait это более полезно, чем для invokeLater.

Paŭlo Ebermann 15.03.2011 01:14

Не видел, чтобы кто-нибудь упоминал instanceof, реализованный таким образом, что проверка на null не требуется.

Вместо:

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

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

if ( aObject instanceof String )
{
    ...
}

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

Peter Dolberg 24.12.2009 19:20

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

Nick Hristov 01.07.2011 08:14

Что еще хуже, проверка на null перед freeing или deleteing в C / C++. Такая фундаментальная концепция.

Thomas Eding 05.02.2012 03:04

мне понравилось

  1. Taglet и doclet javadoc, которые позволяют нам настраивать вывод javadoc.
  2. Инструменты JDK: jstat, jstack и т. д.

Подключаемый модуль Java следующего поколения, найденный в Java 1.6 Update 10 и более поздних версиях, имеет несколько очень полезных функций:

  • Передайте параметр java_arguments, чтобы передать аргументы создаваемой JVM. Это позволяет вам контролировать объем памяти, предоставляемой апплету.
  • Создавайте отдельные загрузчики классов или даже отдельные JVM для каждого апплета.
  • Укажите версию JVM для использования.
  • Устанавливайте частичные ядра Java в тех случаях, когда вам нужна только часть функциональных возможностей полных библиотек Java.
  • Лучшая поддержка Vista.
  • Поддержка (экспериментальная) перетаскивания апплета из браузера и его продолжения при переходе.

Здесь задокументировано много других вещей: http://jdk6.dev.java.net/plugin2/

Больше из этого выпуска здесь: http://jdk6.dev.java.net/6u10ea.html

Вы можете создать строку в стиле sprintf, используя String.format ().

String w = "world";
String s = String.format("Hello %s %d", w, 3);

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

Подробнее здесь: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax

со статическим импортом вы можете делать такие классные вещи, как:

List<String> myList = list("foo", "bar");
Set<String> mySet = set("foo", "bar");
Map<String, String> myMap = map(v("foo", "2"), v("bar", "3"));

вы даже можете сделать это с помощью дженериков. В Google Collections для этого есть хорошие утилиты.

Tim Büthe 27.03.2009 12:39

Мне нравится статический импорт методов.

Например, создайте следующий класс утилиты:

package package.name;

public class util {

     private static void doStuff1(){
        //the end
     }

     private static String doStuff2(){
        return "the end";
     }

}

Тогда используйте это так.

import static package.name.util.*;

public class main{

     public static void main(String[] args){
          doStuff1(); // wee no more typing util.doStuff1()
          System.out.print(doStuff2()); // or util.doStuff2()
     }

}

Статический импорт работает с любым классом, даже Math ...

import static java.lang.Math.*;
import static java.lang.System.out;
public class HelloWorld {
    public static void main(String[] args) {
        out.println("Hello World!");
        out.println("Considering a circle with a diameter of 5 cm, it has:");
        out.println("A circumference of " + (PI * 5) + "cm");
        out.println("And an area of " + (PI * pow(5,2)) + "sq. cm");
    }
}

исправьте регистр буквы «S» в обоих методах doStuffX в вашем примере. Это могло сбивать с толку.

Archer 11.07.2011 10:53

List.subList возвращает представление исходного списка

Документированная, но малоизвестная функция списков. Это позволяет вам работать с частями списка с изменениями, отраженными в исходном списке.

Список подсписок (int fromIndex, int toIndex)

"This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a list can be used as a range operation by passing a subList view instead of a whole list. For example, the following idiom removes a range of elements from a list:

       list.subList(from, to).clear();

Similar idioms may be constructed for indexOf and lastIndexOf, and all of the algorithms in the Collections class can be applied to a subList."

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

lexicalscope 16.11.2010 20:45

И, в зависимости от реализации, некоторые операции с подсписком могут выполняться медленнее, чем с полным списком.

Paŭlo Ebermann 15.03.2011 00:36

Когда люди видят list.subList(from, to).clear(), они приходят в восторг, это так здорово! За исключением того, что в других библиотеках это просто list.RemoveRange(from, to), который намного аккуратнее, прямолинейнее и удобнее.

Pacerier 06.12.2011 08:25

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

не совсем. в какой-то момент вам нужно уточнить: Executors.newSingleThreadExecutor (). submit (new Callable() {..}) - вы не можете создать экземпляр нового Callable> (), вам нужно указать явный тип - таким образом, это альтернатива Callable.

Rahel Lüthy 17.06.2009 18:59

Void более конкретен, чем Object, поскольку Void может быть только нулевым, Object может быть любым.

Peter Lawrey 23.07.2010 01:14

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

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 означает, что я могу определить коллекцию (из пяти) встроенных.

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

slezica 13.10.2011 16:45

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

slezica 05.03.2012 13:12

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

enum Foo1 implements Bar {}
enum Foo2 implements Bar {}

class HelperClass {
   static <T extends Enum<T> & Bar> void fooBar(T the enum) {}
}

Это полезно, когда у вас есть несколько разных перечислений, реализующих какой-то шаблон. Например, несколько пар перечислений, которые связаны родительско-дочерними отношениями.

enum PrimaryColor {Red, Green, Blue;}
enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;}

enum TransportMedium {Land, Sea, Air;}
enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;}

Вы можете написать общие методы, которые говорят: «Хорошо, учитывая значение перечисления, которое является родителем некоторых других значений перечисления, какой процент всех возможных дочерних перечислений дочернего типа имеет это конкретное родительское значение в качестве своего родителя?», И иметь все это безопасный тип и делается без литья. (например: «Море» составляет 33% всех возможных транспортных средств, а «Зеленый» - 20% всех возможных пастелей).

Код выглядит так. Это довольно неприятно, но есть способы исправить это. Обратите внимание, в частности, что сами «листовые» классы довольно аккуратны - общие классы имеют ужасно уродливые объявления, но вы пишете их только один раз. Как только универсальные классы есть, их легко использовать.

import java.util.EnumSet;

import javax.swing.JComponent;

public class zz extends JComponent {

    public static void main(String[] args) {
        System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%");
        System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%");
    }


}

class ParentUtil {
    private ParentUtil(){}
    static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    float pctOf(P parent) {
        return (float) parent.getChildren().size() / //
                (float) EnumSet.allOf(parent.getChildClass()).size() //
                * 100f;
    }
    public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    EnumSet<C> loadChildrenOf(P p) {
        EnumSet<C> cc = EnumSet.noneOf(p.getChildClass());
        for(C c: EnumSet.allOf(p.getChildClass())) {
            if (c.getParent() == p) {
                cc.add(c);
            }
        }
        return cc;
    }
}

interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<C> getChildClass();

    EnumSet<C> getChildren();
}

interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<P> getParentClass();

    P getParent();
}

enum PrimaryColor implements Parent<PrimaryColor, PastelColor> {
    Red, Green, Blue;

    private EnumSet<PastelColor>    children;

    public Class<PastelColor> getChildClass() {
        return PastelColor.class;
    }

    public EnumSet<PastelColor> getChildren() {
        if (children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum PastelColor implements Child<PrimaryColor, PastelColor> {
    Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), //
    Rockmelon(PrimaryColor.Green), //
    SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue);

    final PrimaryColor  parent;

    private PastelColor(PrimaryColor parent) {
        this.parent = parent;
    }

    public Class<PrimaryColor> getParentClass() {
        return PrimaryColor.class;
    }

    public PrimaryColor getParent() {
        return parent;
    }
}

enum TransportMedium implements Parent<TransportMedium, Vehicle> {
    Land, Sea, Air;

    private EnumSet<Vehicle>    children;

    public Class<Vehicle> getChildClass() {
        return Vehicle.class;
    }

    public EnumSet<Vehicle> getChildren() {
        if (children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum Vehicle implements Child<TransportMedium, Vehicle> {
    Car(TransportMedium.Land), Truck(TransportMedium.Land), //
    BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), //
    JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air);

    private final TransportMedium   parent;

    private Vehicle(TransportMedium parent) {
        this.parent = parent;
    }

    public Class<TransportMedium> getParentClass() {
        return TransportMedium.class;
    }

    public TransportMedium getParent() {
        return parent;
    }
}

Прочтите «Java-головоломки» Джошуа Блоха, и вы будете одновременно озарены и испуганы.

URL-адреса исходного кода. Например. вот некоторый законный исходный код Java:

http://google.com

(Да, это было в Java Puzzlers. Я засмеялся ...)

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

Рассмотрим следующий класс:

public class Foo {
    private int bar;

    public Foo() {
        setBar(17);
    }

    private void setBar(int bar) {
        this.bar=bar;
    }

    public int getBar() {
        return bar;
    }

    public String toString() {
        return "Foo[bar = "+bar+"]";
    }
}

Запуск этой программы ...

import java.lang.reflect.*;

public class AccessibleExample {
    public static void main(String[] args)
        throws NoSuchMethodException,IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        Foo foo=new Foo();
        System.out.println(foo);

        Method method=Foo.class.getDeclaredMethod("setBar", int.class);
        method.setAccessible(true);
        method.invoke(foo, 42);

        System.out.println(foo);
        Field field=Foo.class.getDeclaredField("bar");
        field.setAccessible(true);
        field.set(foo, 23);
        System.out.println(foo);
    }
}

... даст следующий результат:

Foo[bar=17]
Foo[bar=42]
Foo[bar=23]

Однако вызов setAccessible может быть запрещен менеджером безопасности.

Paŭlo Ebermann 15.03.2011 01:29

Частичная особенность, частично беспокойство: обработка строк в Java, чтобы он `` казался '' собственным типом (использование операторов на них, +, + =)

Уметь писать:

String s = "A";
s += " String"; // so s == "A String"

очень удобно, но это просто синтаксический сахар для (т.е. компилируется в):

String s = new String("A");
s = new StringBuffer(s).append(" String").toString();

например, создание экземпляра объекта и вызов 2 методов для простой конкатенации. Представьте себе, что вы создаете таким образом длинную строку внутри цикла !? И все методы StringBuffer объявляются синхронизированными. К счастью, в (я думаю) Java 5 они представили StringBuilder, который идентичен StringBuffer без синхронизации.

Цикл, такой как:

String s = "";
for (int i = 0 ; i < 1000 ; ++i)
  s += " " + i; // Really an Object instantiation & 3 method invocations!

можно (нужно) переписать в вашем коде как:

StringBuilder buf = new StringBuilder(); // Empty buffer
for (int i = 0 ; i < 1000 ; ++i)
  buf.append(' ').append(i); // Cut out the object instantiation & reduce to 2 method invocations
String s = buf.toString();

и будет работать примерно на 80% быстрее, чем исходный цикл! (до 180% в некоторых тестах, которые я проводил)

Литерал "A" на самом деле является java.lang.String, хотя его массив поддерживающих символов выделяется другим способом для динамически создаваемых строк.

Donal Fellows 11.06.2010 12:52

Я знал это и испытал. Это происходит потому, что создание и уничтожение объектов - одна из самых дорогих вещей в любом объектно-ориентированном языке. Я слышал однажды ...

John John Pichler 02.03.2011 22:50

Текущие компиляторы будут использовать StringBuilder вместо StringBuffer для конкатенации строк.

Paŭlo Ebermann 15.03.2011 01:16

Пожалуй, самая удивительная скрытая функция - это класс sun.misc.Unsafe.

http://www.docjar.com/html/api/ClassLib/Common/sun/misc/Unsafe.java.html

Вы можете;

  • Создайте объект без вызова конструктора.
  • Выбрасывайте любое исключение, даже Exception, не беспокоясь о предложениях throw для методов. (Я знаю, что есть другой способ сделать это)
  • Получить / установить произвольно доступные поля в объекте без использования отражения.
  • выделить / освободить / скопировать / изменить размер блока памяти, который может быть длинным (64-битным) по размеру.
  • Получите расположение полей в объекте или статических полей в классе.
  • самостоятельно блокировать и разблокировать объектный замок. (например, синхронизировать без блока)
  • определить класс из предоставленных байтовых кодов. Вместо того, чтобы определять, каким должен быть байт-код, загрузчик классов. (Вы также можете сделать это с помощью отражения)

BTW: неправильное использование этого класса убьет JVM. Я не знаю, какие JVM поддерживают этот класс, поэтому его нельзя переносить.

Это не скрытая функция Java, а скрытая функция некоторых конкретных реализаций JVM.

Nat 13.08.2009 17:15

Верно, хотя я не встречал JSE, в котором его нет. Если кто-нибудь знает кого-нибудь, мне было бы интересно.

Peter Lawrey 15.08.2009 14:02

вы имеете в виду oracle.misc.Unsafe? :) Помню, когда я это обнаружил (заглянул внутрь реализации солнечного jvm AtomicInteger) и был совершенно очарован

Mauricio 18.01.2011 03:50

Я не видел его под названием oracle. * Думаю, когда-нибудь они смогут переименовать его.

Peter Lawrey 18.01.2011 09:42

Недавно я использовал его для выделения блока размером 16 ГБ (чего нельзя сделать в Java), для заполнения которого потребовалось 30 секунд. Я действительно мог видеть основную память как новый диск. ;)

Peter Lawrey 18.01.2011 09:45

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

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

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

ChaosPandion 12.07.2010 20:49

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

Thorbjørn Ravn Andersen 03.12.2010 17:19

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

Axel 02.08.2011 12:35

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

AmigoNico 08.01.2012 10:02

Уловка оптимизации, которая упрощает обслуживание вашего кода и делает его менее уязвимым для ошибок параллелизма.

public class Slow {
  /** Loop counter; initialized to 0. */
  private long i;

  public static void main( String args[] ) {
    Slow slow = new Slow();

    slow.run();
  }

  private void run() {
    while( i++ < 10000000000L )
      ;
  }
}

$ time java Slow
реальный 0m15.397s
$ time java Slow
реальный 0m20.012s
$ time java Slow
реальный 0m18.645s

Среднее: 18.018 с

public class Fast {
  /** Loop counter; initialized to 0. */
  private long i;

  public static void main( String args[] ) {
    Fast fast = new Fast();

    fast.run();
  }

  private void run() {
    long i = getI();

    while( i++ < 10000000000L )
      ;

    setI( i );
  }

  private long setI( long i ) {
    this.i = i;
  }

  private long getI() {
    return this.i;
  }
}

$ time java Fast
реальный 0m12.003s
$ time java Fast
реальный 0m9.840s
$ time java Fast
реальный 0m9.686s

Среднее: 10,509 с

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

Еще одно преимущество этого метода (всегда использующего аксессоры) состоит в том, что он устраняет потенциальную ошибку в классе Медленный. Если бы второй поток постоянно сбрасывал значение я в 0 (например, вызывая slow.setI( 0 )), класс Медленный никогда не смог бы завершить свой цикл. Вызов метода доступа и использование локальной переменной исключает эту возможность.

Протестировано с использованием J2SE 1.6.0_13 в Linux 2.6.27-14.

но Fast - это не то же самое, что Slow: значение члена Fast.i НЕ изменяется после цикла. Если вы вызовете метод run () второй раз, Slow будет намного быстрее (увеличивает "i" только один раз), а Fast будет таким же медленным, как раньше, поскольку "Fast.i" по-прежнему равен нулю.

user85421 22.06.2009 21:19

Вы правы, Карлос. Чтобы обеспечить одинаковое поведение Fast и Slow (в однопоточной среде), переменная экземпляра «i» должна быть обновлена ​​в конце метода «run», что не окажет существенного влияния на производительность.

Dave Jarvis 23.06.2009 00:56

также получил "странный" результат с использованием System.currentTimeMillis () вокруг вызова для расчета времени выполнения: медленное быстрее, чем быстрое (медленное = 40,6 с, быстрое = 42,9 с) для 1.6.0_13-b03 на WindowsXP

user85421 23.06.2009 03:22

Карлос: Попробуйте выполнить четыре прогона для обоих классов без запуска каких-либо потенциально интенсивных программ (например, антивирусной программы, обновления системы, браузера). Кроме того, выбрасывайте первую пробежку в обоих тестовых залпах. Этот Fast на ~ 2 секунды медленнее, чем Slow, заставляет меня поверить, что что-то мешает бегу. (То есть получение и установка переменной с помощью метода доступа не должно занимать 2 секунды.)

Dave Jarvis 23.06.2009 03:50

«Преждевременная оптимизация» - это фраза, используемая для описания ситуации, когда программист позволяет соображениям производительности влиять на дизайн фрагмента кода. Это может привести к тому, что дизайн будет не таким чистым, как мог бы, или к некорректному коду, потому что код усложняется оптимизацией, а программист отвлекается на оптимизацию. [ref: en.wikipedia.org/wiki/Optimization_%28computer_science%29]

jdigital 13.08.2009 04:26

@jdigital: Я не считаю это преждевременным. Когда методы синхронизированы, это защищает от следующей проблемы: stackoverflow.com/questions/2458217/…

Dave Jarvis 28.07.2010 03:02

Методы доступа к свойствам Java Bean действительно должны начинаться с нет с «get» и «set».

Даже Джош Блох ошибается в Effective Java.

Ну, конечно, нет, это скорее соглашение о коде. Многие фреймворки / API полагаются на отражение для доступа к вашим свойствам, поэтому отказ от использования get (is) / set просто вызывает проблемы.

serg 13.07.2009 03:06

Это доказывает мою точку зрения. Использование префиксов get / set взято из API Java Beans и является просто соглашением об именах по умолчанию, а не обязательным. Но авторы плохо спроектированных фреймворков / API, похоже, этого не знают. Они жестко кодируют соглашение об именах, которое классы должны использовать для работы с их фреймворком (а затем имеют наглость сказать, что их фреймворк поддерживает POJO; обязательное соглашение об именовании, по определению, делает их фреймворк не поддерживать POJO).

Nat 13.08.2009 17:14

Я только что (заново) узнал сегодня, что $ - это допустимое имя метода или переменной в Java. В сочетании со статическим импортом он может сделать код немного более читаемым, в зависимости от вашего представления о читаемости:

http://garbagecollected.org/2008/04/06/dollarmaps/

Символ $ также используется для отличия внутренних классов от их классов в большинстве компиляторов.

Dave Jarvis 13.08.2009 06:15

Вы также можете использовать знаки £ и € в именах переменных. А также любые буквы UNICODE æ, ø, å и т. д.

Andrey Adamovich 27.10.2009 13:24

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

Другой, возможно, лучший и менее уродливый подход - использовать класс AtomicReference (или AtomicBoolean / AtomicInteger /…) из пакета java.util.concurrent.atomic.

Одним из преимуществ этого является то, что эти классы также предоставляют такие методы, как compareAndSet, которые могут быть полезны, если вы создаете несколько потоков, которые могут изменять одну и ту же переменную.


Еще один полезный родственный шаблон:

final AtomicBoolean dataMsgReceived = new AtomicBoolean(false);
final AtomicReference<Message> message = new AtomicReference<Message>();
withMessageHandler(new MessageHandler() {
    public void handleMessage(Message msg) {
         if (msg.isData()) {
             synchronized (dataMsgReceived) {
                 message.set(msg);
                 dataMsgReceived.set(true);
                 dataMsgReceived.notifyAll();
             }
         }
    }
}, new Interruptible() {
    public void run() throws InterruptedException {
        synchronized (dataMsgReceived) {
            while (!dataMsgReceived.get()) {
                dataMsgReceived.wait();
            }
        }
    }
});

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

waitMessageHandler(…), приведенный выше, является еще одним полезным шаблоном: он где-то устанавливает обработчик, затем запускает выполнение Прерывистый, которое может вызвать исключение, а затем удаляет обработчик в блоке finally, например:

private final AtomicReference<MessageHandler> messageHandler = new AtomicReference<MessageHandler>();
public void withMessageHandler(MessageHandler handler, Interruptible logic) throws InterruptedException {
    synchronized (messageHandler) {
        try {
            messageHandler.set(handler);
            logic.run();
        } finally {
            messageHandler.set(null);
        }
    }
}

Здесь я предполагаю, что метод handleMessage(…)messageHandler (если он не нулевой) вызывается другим потоком при получении сообщения. messageHandler не должен быть просто типа MessageHandler: таким образом вы будете синхронизироваться с изменяющейся переменной, что явно является ошибкой.

Конечно, это не обязательно должно быть InterruptedException, это может быть что-то вроде IOException или что-то еще, что имеет смысл в конкретном фрагменте кода.

Запятая и массив. Это допустимый синтаксис: String s [] = {
«123»,
«234» ,
};

У меня был разрыв запятой в определенной версии javac, 1.6.0_13 или 17, я думаю

gtrak 13.01.2012 23:17

Большинство людей не знают, что они могут клонировать массив.

int[] arr = {1, 2, 3};
int[] arr2 = arr.clone();

Вы можете вызвать в clone на любой Object. Вам просто нужно быть осторожным, чтобы Object реализовал глубокий клон.

Finbarr 13.05.2010 15:12

@Finbarr: Скорее наоборот. Это мелкий клон; внутренние объекты просто получают еще одну ссылку на них. Самый «простой» способ глубокого клонирования - сериализовать и десериализовать или действительно понять, что вы делаете копию.

Donal Fellows 11.06.2010 12:56

@Finbar: нельзя вызывать clone для любого объекта, только для объектов из классов, которые сделали этот метод общедоступным, или из текущего класса.

Paŭlo Ebermann 15.03.2011 01:27

Используйте StringBuilder вместо StringBuffer, если вам не нужно синхронизированное управление, включенное в StringBuilder. Это повысит производительность вашего приложения.

Улучшения для Java 7 были бы даже лучше, чем любые скрытые функции Java:

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

Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

// Can now be replaced with this:

Map<String, List<String>> anagrams = new HashMap<>();
  • Строки в переключателе:Связь

Используйте String в переключателе вместо old-C int:

String s = "something";
switch(s) {
 case "quux":
    processQuux(s);
    // fall-through

  case "foo":
  case "bar":
    processFooOrBar(s);
    break;

  case "baz":
     processBaz(s);
    // fall-through

  default:
    processDefault(s);
    break;
}
  • Автоматическое управление ресурсамиСвязь

Этот старый код:

static void copy(String src, String dest) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dest);
        try {
            byte[] buf = new byte[8 * 1024];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

теперь его можно заменить более простым кодом:

static void copy(String src, String dest) throws IOException {
    try (InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest)) {
        byte[] buf = new byte[8192];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);
    }
}

Вы имеете в виду StringBuilder вместо StringWriter? API для StringBuffer и StringBuilder одинаковы, однако использование StringWriter потребует некоторых изменений кода.

pjp 07.12.2009 15:15

На самом деле он имел в виду StringBuilder, который не является поточно-ориентированным, но более быстрым. StringBuffer является потокобезопасным, но медленнее. Следует использовать только в том случае, если вам нужна потокобезопасность при создании строкового буфера.

Archer 11.07.2011 10:51

Вы можете переключить (это) внутри определений методов классов перечисления. Заставил меня крикнуть "ах!" громко, когда я обнаружил, что это действительно работает.

Да, переключатель работает с выражениями перечисления в целом, а не только внутри классов перечисления.

Paŭlo Ebermann 15.03.2011 01:49

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

Возможно, большинство людей знают, что Collections.synchronizedList () добавляет синхронизацию в список. Чего вы не можете знать, если не прочитаете документацию, так это того, что вы можете безопасно выполнять итерацию по элементам этого списка, синхронизируя сам объект списка.

CopyOnWriteArrayList может быть неизвестен некоторым, а Future представляет интересный способ абстрактного многопоточного доступа к результатам.

Вы можете подключаться к виртуальным машинам (локальным или удаленным), получать информацию об активности сборщика мусора, использовании памяти, файловых дескрипторах и даже размерах объектов с помощью различных API-интерфейсов управления, агентов и подключения.

Хотя TimeUnit, возможно, лучше, чем long, я предпочитаю класс Duration от Wicket.

О, я чуть не забыл эту маленькую жемчужину. Попробуйте это на любом запущенном java-процессе:

jmap -histo: live PID

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

Функция, с помощью которой вы можете отображать заставки для консольных приложений Java.

Используйте инструмент командной строки java или javaw с параметром -splash.

например:

java -splash:C:\myfolder\myimage.png -classpath myjarfile.jar com.my.package.MyClass

содержимое C:\myfolder\myimage.png будет отображаться в центре экрана всякий раз, когда вы выполняете класс "com.my.package.MyClass"

Это действительно скрыто ... не могу найти параметр в документации для команды java (java.exe). (но это в справочном сообщении или в javadoc SplashScreen)

user85421 27.11.2009 13:41

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

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

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

Devon_C_Miller 02.06.2010 18:40

Меня удивляет, что интерфейс может расширять несколько интерфейсов, но класс может расширять только один класс.

Не совсем. Никогда не возникает проблем с тем, «какая реализация суперкласса должна быть вызвана», поскольку нет реализаций.

WhyNotHugo 03.01.2010 05:56

Как бы вы расширили 2 класса с одинаковым методом? Какой метод войдет в окончательную реализацию?

Archer 11.07.2011 11:06

На самом деле возможно множественное наследование @archer. В этом случае, как вы указываете, мы можем просто отклонить это или использовать один из методов разрешения конфликтов имен.

Pacerier 07.12.2011 16:53

Подстановочные знаки пути к классам начиная с Java 6.

java -classpath ./lib/* so.Main

Вместо

java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main

См. http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html

Хуки выключения. Это позволяет зарегистрировать поток, который будет создан немедленно, но запустится только после завершения JVM! Так что это своего рода «глобальный финализатор jvm», и вы можете делать полезные вещи в этом потоке (например, отключать ресурсы Java, такие как встроенный сервер hsqldb). Это работает с System.exit () или с CTRL-C / kill -15 (но, конечно, не с kill -9 в unix).

Более того, это довольно просто настроить.

            Runtime.getRuntime().addShutdownHook(new Thread() {
                  public void run() {
                      endApp();
                  }
            });;

Они великолепны! Вы также можете отменить регистрацию их (если вы сохраните ссылку), чтобы вы могли хорошо очистить ресурсы. Я использую их - в сочетании с обратными вызовами жизненного цикла Spring, особенно атрибутом destroy-method - для отключения подпроцессов рабочих.

Donal Fellows 11.06.2010 12:05

Обратите внимание, что перехватчики завершения работы не выполняются, если вызывается Runtime.halt ().

Esko Luontola 25.02.2011 15:23

Перехватчики завершения работы не вызываются в Windows, если javaw используется для запуска приложения и инициируется выход из системы Windows. Должно быть консольное окно. Вздох. Я пытался использовать это, чтобы отметить меня как «вне офиса» на нашем веб-сайте, и мне пришлось жить с минимизированным окном консоли.

Chris Mazzola 22.06.2011 00:02

Идентификаторы могут содержать символы иностранного языка, например умляуты:

вместо написания:

String title = "";

кто-то мог написать:

String Überschrift = "";

и вы можете получить к нему доступ как \u00dcberschrift = "OK";

user85421 10.01.2010 02:11

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

Werner Lehmann 25.03.2010 03:35

Проблема не столько в том, что в любом проекте реального размера будут разработчики, говорящие на разных языках ... Проблема в том, что в любом проекте реального размера должен представляет собой смесь Windows, а текстовые файлы Unx (включая OS X) и сочетание разных IDE с разными настройками. Объедините это с факт, что * .java не имеют метаданных, описывающих их кодировки файлов. ни хороших спецификаций (спецификации допускают любую кодировку символов), и у вас есть свой рецепт катастрофы. Программисты Java, использующие символы, отличные от ASCII, внутри идентификаторов String of in, заслуживают смерти.

SyntaxT3rr0r 21.12.2010 02:30

Строки, отличные от ASCII, должны быть экстернализованы, а сценарии сборки и / или верификаторы перед фиксацией должны быть сконфигурированы так, чтобы сразу же отказываться при обнаружении такой бессмысленной бессмыслицы. Наши сценарии сборки Ant потерпят неудачу и поставят любого разработчика, пытающегося это сделать, на стену стыда.

SyntaxT3rr0r 21.12.2010 02:32

Java 6 (от Sun) поставляется со встроенным интерпретатором JavaScrip.

http://java.sun.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#jsengine

Пример использования: java2s.com/Code/Java/JDK-6/…

Paul Lysak 25.03.2011 11:16

Не читал об этом

Integer a = 1;
Integer b = 1;
Integer c = new Integer(1);
Integer d = new Integer(1);

Integer e = 128;
Integer f = 128;

assertTrue (a == b);   // again: this is true!
assertFalse(e == f); // again: this is false!
assertFalse(c == d);   // again: this is false!

узнайте больше об этом, выполнив поиск в пуле целых чисел Java (внутренний «кеш» от -128 до 127 для автобокса) или загляните в Integer.valueOf

Точный предел зависит от реализации (имеет только некоторый минимальный размер), поэтому на некоторых виртуальных машинах второй тест тоже может быть верным.

Paŭlo Ebermann 15.03.2011 01:51

Верно ли говорить, что третий тест будет ложный независимо от ВМ?

Pacerier 07.12.2011 16:45

@Pacerier, если честно. Точно сказать не могу. но это сработало в то время, когда я публиковал это ... просто не зависит от оператора == ...

Karussell 08.12.2011 01:40

Итак, они используют указатель для хранения небольших целочисленных значений, не так ли?

Hejazzman 08.01.2012 18:18

Это указано в Спецификации языка Java для диапазона [-127,127]. Что касается других целых чисел, я не уверен

Miguel Ping 09.01.2012 18:45

Вы можете переопределить метод и вызвать его конструктор суперкласса (это может стать сюрпризом для программистов на C++).

Пример

Это может привести к множеству проблем. Учтите это: класс B расширяет класс A и переопределяет метод doSomething (), который вызывается конструктором A. Теперь конструкторы вызываются в базовом -> производном порядке, но конструктор A вызывает функцию doSomething () B. B инициализирован?

ivant 15.11.2011 12:23

Вот мой список.

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

import java.rmi.RemoteException;

class Thrower {
    public static void spit(final Throwable exception) {
        class EvilThrower<T extends Throwable> {
            @SuppressWarnings("unchecked")
            private void sneakyThrow(Throwable exception) throws T {
                throw (T) exception;
            }
        }
        new EvilThrower<RuntimeException>().sneakyThrow(exception);
    }
}

public class ThrowerSample {
    public static void main( String[] args ) {
        Thrower.spit(new RemoteException("go unchecked!"));
    }
}

Также вам может быть интересно узнать, что вы можете выбросить 'null' ...

public static void main(String[] args) {
     throw null;
}

Угадайте, что это печатает:

Long value = new Long(0);
System.out.println(value.equals(0));

И угадайте, что это вернет:

public int returnSomething() {
    try {
        throw new RuntimeException("foo!");
    } finally {
        return 0;
    }
}

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


В Java вы можете объявить массив следующими допустимыми способами:

String[] strings = new String[] { "foo", "bar" };
// the above is equivalent to the following:
String[] strings = { "foo", "bar" };

Итак, следующий код Java вполне допустим:

public class Foo {
    public void doSomething(String[] arg) {}

    public void example() {
        String[] strings = { "foo", "bar" };
        doSomething(strings);
    }
}

Есть ли веская причина, по которой следующий код не должен быть действительным?

public class Foo {

    public void doSomething(String[] arg) {}

    public void example() {
        doSomething({ "foo", "bar" });
    }
}

Я думаю, что приведенный выше синтаксис мог бы заменить varargs, введенный в Java 5. И более согласованный с ранее разрешенными объявлениями массивов.

Веская причина в том, что компилятор не может определить тип массива. Но хороший список.

CurtainDog 19.02.2010 08:36

Разве doSomething ({"", ""}) не будет поддерживаться простыми замыканиями в Java 7?

Shervin Asgari 08.04.2010 12:57

относительно вашего комментария о "хорошие разработчики" и попробуй / наконец головоломке плохого стиля, которая-никогда-не-в-дикой природе ... Что ж, у хороших разработчиков есть IDE, которая будет предупреждать их в реальном времени, даже при неполном AST, что "такие операторы возврата (внутри блоков finally) могут маскировать выброшенное исключение" . Кто сейчас плохие разработчики, использующие второстепенные IDE? ;)

SyntaxT3rr0r 21.12.2010 02:26

@ SyntaxT3rr0r: Хорошие разработчики - это те, кто знает больше, чем IDE, которую они используют, может обнаружить, поскольку большинство ошибок логики / кодирования не обнаруживаются IDE.

Luigi R. Viggiano 28.01.2011 19:25

throw null должен дать вам NullPointerException во время выполнения.

Paŭlo Ebermann 15.03.2011 00:27

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

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

Вы можете добавить проверки общих типов во время выполнения с помощью объекта Class<T>, это удобно, когда класс создается где-то в файле конфигурации и нет возможности добавить проверку времени компиляции для универсального типа класса. Вы не хотите, чтобы класс взорвался во время выполнения, если приложение неправильно настроено, и вы не хотите, чтобы все ваши классы были пронизаны экземплярами проверок.

public interface SomeInterface {
  void doSomething(Object o);
}
public abstract class RuntimeCheckingTemplate<T> {
  private Class<T> clazz;
  protected RuntimeChecking(Class<T> clazz) {
    this.clazz = clazz;
  }

  public void doSomething(Object o) {
    if (clazz.isInstance(o)) {
      doSomethingWithGeneric(clazz.cast(o));
    } else {
      // log it, do something by default, throw an exception, etc.
    }
  }

  protected abstract void doSomethingWithGeneric(T t);
}

public class ClassThatWorksWithStrings extends RuntimeCheckingTemplate<String> {
  public ClassThatWorksWithStrings() {
     super(String.class);
  }

  protected abstract void doSomethingWithGeneric(T t) {
    // Do something with the generic and know that a runtime exception won't occur 
    // because of a wrong type
  }
}

Я был удивлен, когда впервые заметил тернарный оператор, равный простому выражению if-then-else:

minVal = (a < b) ? a : b;

IMHO это не скрыто и не удивительно, большинство языков, которые я знаю, имеют это (C, C++, C#, PHP, Perl, Javascript, ...)

Morfildur 09.04.2010 16:18

Я знаю это сейчас, но несколько недель назад я не думал о таком операторе. Наверное, потому, что я не слишком опытен, но мой разум был несколько взорван: D

user312723 09.04.2010 16:36

Я согласен с @dbermerlin. Это НЕ скрытая функция. Это очень распространено.

Shervin Asgari 10.04.2010 20:24

Я могу добавить объект сканера. Лучше всего подходит для разбора.

String input = "1 fish 2 fish red fish blue fish";
Scanner s = new Scanner(input).useDelimiter("\s*fish\s*");
System.out.println(s.nextInt());
System.out.println(s.nextInt());
System.out.println(s.next());
System.out.println(s.next());
s.close();

На мой взгляд, это не скрытая особенность. Сканер - это библиотека.

Shervin Asgari 09.06.2010 13:17

Вы можете определять и вызывать методы анонимных внутренних классов.

Ну, они не так уж и скрыты, но мало кто знает, что с их помощью можно определить новый метод в классе и вызвать его следующим образом:

(new Object() {
    public String someMethod(){ 
        return "some value";
    }
}).someMethod();

Вероятно, это не очень распространено, потому что это тоже не очень полезно, вы можете вызвать метод Только, когда вы его определяете (или через отражение)

Немного похоже на шаблон модуля JavaScript;)

Johannes Wachter 23.08.2010 16:02

На самом деле это не скрытая функция, но я очень удивился, когда увидел этот скомпилированный штраф:

public int aMethod(){
    http://www.google.com
    return 1;
}

причина, по которой он компилируется, заключается в том, что строка http://www.google.com в части «http:» обрабатывается компилятором как метка, а остальная часть строки является комментарием.

Итак, если вы хотите написать какой-то причудливый код (или запутанный код), просто поместите туда много http-адресов. ;-)

но старше года. См. Этот ответ Дэвида Пламптона от 12 мая 2009 г .: stackoverflow.com/questions/15496/hidden-features-of-java/… (и он получил только 2 голоса за ...)

user85421 28.06.2010 12:21

Это повторяющийся ответ

Shervin Asgari 28.06.2010 13:55

... и он работает максимум с одним http-адресом для каждого метода, поскольку метки должны быть уникальными.

Paŭlo Ebermann 15.03.2011 00:41

Функция printf () в стиле C :)

System.out.printf("%d %f %.4f", 3,Math.E,Math.E);

Выход: 3 2,718282 2,7183

Двоичный поиск (и его возвращаемое значение)

int[] q = new int[] { 1,3,4,5};
int position = Arrays.binarySearch(q, 2);

Как и в C#, если «2» не найден в массиве, он возвращает отрицательное значение, но если вы возьмете дополнение 1 возвращаемого значения, вы фактически получите позицию, в которую можно вставить «2».

В приведенном выше примере позиция = -2, ~ позиция = 1, которая является позицией, в которую следует вставить 2 ... она также позволяет вам найти «ближайшее» совпадение в массиве.

Думаю, это здорово ... :)

printf не скрыт, как и работа binarySearch.

user85421 30.06.2010 16:04

Ни одна из функций, упомянутых в предыдущих ответах, не является точно «скрытой». Большинство из них просто «относительно неизвестны» обычному программисту Java. По крайней мере, я думал, что это был вопрос ...

st0le 30.06.2010 17:01

Не так уж и скрыто, но интересно.

У вас может быть «Hello, world» без основного метода (это вызывает мысль NoSuchMethodError)

Первоначально опубликовано RusselW на Самая странная языковая функция

public class WithoutMain {
    static {
        System.out.println("Look ma, no main!!");
        System.exit(0);
    }
}

$ java WithoutMain
Look ma, no main!!

Добавьте System.exit(0);, чтобы подавить это ужасное исключение ...

Donal Fellows 13.07.2010 03:36

Это простое злоупотребление статической инициализацией, я бы ничего не стал рассматривать как особенность ...

pdinklag 18.07.2011 13:27

Другие вопросы по теме