После прочтения Скрытых особенностей С# я подумал:" Каковы некоторые скрытые возможности Java?
Скрытые особенности Java
Ответ 1
Двойная инициализация Brace заставила меня врасплох несколько месяцев назад, когда я впервые обнаружил ее, никогда не слышал об этом раньше.
ThreadLocals обычно не так широко известны как способ хранения состояния в потоке.
Так как JDK 1.5 Java имеет чрезвычайно хорошо реализованные и надежные инструменты concurrency, помимо просто блокировок, они живут в java.util.concurrent и особенно интересным примером является java.util.concurrent.atomic subpackage, который содержит поточно-безопасные примитивы, которые реализуют compare and-swap и может отображать фактические версии поддерживаемых аппаратных версий этих операций.
Ответ 2
Объединенный союз в дисперсии параметра типа:
public class Baz<T extends Foo & Bar> {}
Например, если вы хотите использовать параметр, сопоставляемый как Comparable, так и Collection:
public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}
Этот надуманный метод возвращает true, если две указанные коллекции равны или если один из них содержит данный элемент, в противном случае - false. Следует заметить, что вы можете вызывать методы как Comparable, так и Collection для аргументов b1 и b2.
Ответ 3
На днях я был удивлен инициализаторами экземпляров. Я удалял некоторые сложенные кодом методы и в итоге создал несколько инициализаторов экземпляров:
public class App {
public App(String name) { System.out.println(name + " 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 constructor called
instance initializer called
instance initializer2 called
two 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");
}};
Ответ 4
JDK 1.6_07 + содержит приложение под названием VisualVM (bin/jvisualvm.exe), которое является хорошим графическим интерфейсом поверх многих инструментов. Это кажется более полным, чем JConsole.
Ответ 5
Классовые карты класса path, начиная с 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
Ответ 6
Для большинства людей я беру интервью для позиций разработчиков 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 - это просто ключевое слово?:)
Ответ 7
Как насчет ковариантных типов возврата, которые были установлены с JDK 1.5? Он довольно слабо рекламируется, поскольку он является дополнением unsexy, но, как я понимаю, абсолютно необходимо, чтобы дженерики работали.
По сути, теперь компилятор позволяет подклассу сузить возвращаемый тип переопределенного метода как подкласс исходного типа возвращаемого метода. Так что это разрешено:
class Souper {
Collection<String> values() {
...
}
}
class ThreadSafeSortedSub extends Souper {
@Override
ConcurrentSkipListSet<String> values() {
...
}
}
Вы можете вызвать метод подкласса values
и получить упорядоченный поток Set
Set
String
без необходимости припуска вниз к ConcurrentSkipListSet
.
Ответ 8
Передача управления в блоке 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
Ответ 9
Не видел, чтобы кто-то упоминал, что экземпляр реализован таким образом, что проверка нулевого значения не требуется.
Вместо:
if( null != aObject && aObject instanceof String )
{
...
}
просто используйте:
if( aObject instanceof String )
{
...
}
Ответ 10
Допустимые методы и конструкторы в перечислениях меня удивили. Например:
enum Cats {
FELIX(2), SHEEBA(3), RUFUS(7);
private int mAge;
Cats(int age) {
mAge = age;
}
public int getAge() {
return mAge;
}
}
У вас может даже быть "постоянное конкретное тело класса", которое позволяет определенному значению перечисления переопределять методы.
Дополнительная документация здесь.
Ответ 11
Параметры param для общих методов могут быть указаны явно следующим образом:
Collections.<String,Integer>emptyMap()
Ответ 12
Вы можете использовать перечисления для реализации интерфейса.
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; }
}
EDIT: спустя годы....
Я использую эту функцию здесь
public enum AffinityStrategies implements AffinityStrategy {
Используя интерфейс, разработчики могут определять свои собственные стратегии. Использование enum
означает, что я могу определить коллекцию (из пяти), встроенную в них.
Ответ 13
Начиная с Java 1.5, Java теперь имеет более чистый синтаксис для записи функций переменной arity. Таким образом, вместо простого прохождения массива теперь вы можете сделать следующее
public void foo(String... bars) {
for (String bar: bars)
System.out.println(bar);
}
Строки автоматически преобразуются в массив указанного типа. Не огромная победа, но победа, тем не менее.
Ответ 14
Мой любимый: отбросить все стеки стека потока до стандартного.
windows: CTRL - Break в окне java cmd/console
unix: kill -3 PID
Ответ 15
Несколько человек отправили об инициализаторах экземпляров, здесь хорошо для этого:
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");
}
});
}});
}});
}};
Ответ 16
Динамические прокси (добавлено в 1.3) позволяют вам определять новый тип во время выполнения, соответствующий интерфейсу. Это пригодится удивительное количество раз.
Ответ 17
окончательная инициализация может быть отложена.
Он гарантирует, что даже при наличии сложного потока логических возвращаемых значений всегда задаются. Это слишком легко пропустить случай и возвратить 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;
}
Ответ 18
Я думаю, что другая "пропущенная" особенность java - это сама JVM. Вероятно, это лучшая виртуальная машина. И он поддерживает множество интересных и полезных языков (Jython, JRuby, Scala, Groovy). Все эти языки могут легко и легко взаимодействовать.
Если вы создаете новый язык (например, в scala -case), вы сразу же получаете все существующие библиотеки, и поэтому ваш язык "очень полезен" с самого начала.
Все эти языки используют оптимизацию HotSpot. VM очень хорошо контролирует и отлаживает.
Ответ 19
Вы можете определить анонимный подкласс и напрямую вызвать на нем метод, даже если он не реализует никаких интерфейсов.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
Ответ 20
Метод asList в java.util.Arrays
позволяет легко сочетать varargs, общие методы и autoboxing:
List<Integer> ints = Arrays.asList(1,2,3);
Ответ 21
Использование этого ключевого слова для доступа к полям/методам содержащего класс из внутреннего класса. В приведенном ниже примере, скорее надуманном, мы хотим использовать класс 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;
}
}
Ответ 22
Не совсем особенность, но забавный трюк, который я недавно обнаружил на какой-то веб-странице:
class Example
{
public static void main(String[] args)
{
System.out.println("Hello World!");
http://Phi.Lho.free.fr
System.exit(0);
}
}
- действительная Java-программа (хотя она генерирует предупреждение). Если вы не видите, почему, см. Ответ Григория!;-) Ну, подсветка синтаксиса здесь также дает подсказку!
Ответ 23
Это не совсем "скрытые возможности" и не очень полезны, но могут быть чрезвычайно интересными в некоторых случаях:
Класс 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);
}
};
}
Ответ 24
При работе в Swing мне нравится скрытая функция Ctrl - Shift - F1.
Он выгружает дерево компонентов текущего окна.
(Предполагая, что вы не связали это нажатие клавиши с чем-то другим.)
Ответ 25
Каждый файл класса начинается с шестнадцатеричного значения 0xCAFEBABE, чтобы идентифицировать его как действительный байт-код JVM.
Ответ 26
Мое голосование переходит к java.util.concurrent с его параллельными коллекциями и гибкими исполнителями, позволяющими, среди прочего, пулы потоков, запланированные задачи и скоординированные задачи. DelayQueue - мой личный фаворит, где элементы становятся доступными после определенной задержки.
java.util.Timer и TimerTask можно безопасно отложить.
Кроме того, не совсем скрыто, но в другом пакете из других классов, связанных с датой и временем. java.util.concurrent.TimeUnit полезен при преобразовании между наносекундами, микросекундами, миллисекундами и секундами.
Он читается намного лучше, чем обычный someValue * 1000 или someValue/1000.
Ответ 27
Ключевое слово assert на уровне языка.
Ответ 28
Не является частью языка Java, но дизассемблер javap, который поставляется с Sun JDK, широко не известен и не используется.
Ответ 29
Добавление конструкции для каждого цикла в 1.5. я < 3 it.
// 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;
}
Ответ 30
я лично обнаружил java.lang.Void
очень поздно - улучшает читаемость кода в сочетании с дженериками, например. Callable<Void>