После прочтения скрытых возможностей C # я задумался: каковы некоторые скрытые возможности Java?
После прочтения скрытых возможностей C # я задумался: каковы некоторые скрытые возможности Java?
Ответы:
Инициализация двойной скобки застала меня врасплох несколько месяцев назад, когда я впервые обнаружил это, никогда не слышал об этом раньше.
ThreadLocals обычно не так широко известны как способ хранения состояния для каждого потока.
Поскольку в Java JDK 1.5 реализованы чрезвычайно надежные и надежные инструменты параллелизма, помимо просто блокировок, они живут в java.util.concurrent, и особенно интересным примером является подпакет java.util.concurrent.atomic, который содержит потокобезопасные примитивы, которые реализуют сравнение -and-swap операция и может отображаться на реальные версии этих операций с аппаратной поддержкой.
Совместное объединение в дисперсии параметров типа:
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.
Я был удивлен инициализаторами экземпляра на днях. Я удалил некоторые методы, свернутые в коде, и в итоге создал несколько инициализаторов экземпляров:
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");
}};
JDK 1.6_07 + содержит приложение под названием VisualVM (bin / jvisualvm.exe), которое представляет собой приятный графический интерфейс поверх многих инструментов. Это кажется более полным, чем JConsole.
Подстановочные знаки Classpath начиная с 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.
Для большинства людей, у которых я беру интервью на должности разработчиков 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 это просто ключевое слово? :)
Как насчет ковариантных типов возвращаемых данных, которые существуют с JDK 1.5? Это довольно плохо публикуется, так как это несексуальное дополнение, но, насколько я понимаю, абсолютно необходимо для работы дженериков.
По сути, компилятор теперь позволяет подклассу сузить тип возвращаемого значения переопределенного метода, чтобы он был подклассом возвращаемого типа исходного метода. Так что это разрешено:
class Souper {
Collection<String> values() {
...
}
}
class ThreadSafeSortedSub extends Souper {
@Override
ConcurrentSkipListSet<String> values() {
...
}
}
Вы можете вызвать метод подкласса values
и получить отсортированный поток, безопасный Set
для String
s, без необходимости приведения к типу ConcurrentSkipListSet
.
Передача контроля в блоке 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
Никто не упомянул, что instanceof реализован таким образом, что проверка на нулевое значение не требуется.
Вместо того:
if( null != aObject && aObject instanceof String )
{
...
}
просто используйте:
if( aObject instanceof String )
{
...
}
free
загрузкой или delete
загрузкой в C / C ++. Такая фундаментальная концепция.
Разрешение методов и конструкторов в перечислениях удивило меня. Например:
enum Cats {
FELIX(2), SHEEBA(3), RUFUS(7);
private int mAge;
Cats(int age) {
mAge = age;
}
public int getAge() {
return mAge;
}
}
Вы даже можете иметь «постоянное тело определенного класса», которое позволяет определенному значению перечисления переопределять методы.
Больше документации здесь .
mAge
должен быть окончательным. В перечислениях редко встречается причина нефинальных полей.
Типовые параметры для универсальных методов могут быть указаны явно так:
Collections.<String,Integer>emptyMap()
public static <T> T foo(T t)
. Затем вы можете позвонитьClass.<Type>foo(t);
return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList()
. Это также полезно для некоторых вызовов методов, где простой Collections.emptyMap () может привести к ошибке компиляции.
Вы можете использовать перечисления для реализации интерфейса.
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 {
Используя интерфейс, разработчики могут определять свои собственные стратегии. Используяenum
средства, я могу определить коллекцию (из пяти) встроенных.
Начиная с Java 1.5, Java теперь имеет гораздо более чистый синтаксис для написания функций переменной арности. Таким образом, вместо того, чтобы просто передать массив, теперь вы можете сделать следующее
public void foo(String... bars) {
for (String bar: bars)
System.out.println(bar);
}
бары автоматически преобразуются в массив указанного типа. Не огромная победа, но, тем не менее, победа.
Мое любимое: сбросить все трассировки стека потоков в стандартный вывод.
Windows: CTRL- Breakв вашем окне Java CMD / консоли
UNIX: kill -3 PID
Break
клавиша.
Несколько человек написали об инициализаторах экземпляров, вот хорошее применение для этого:
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");
}
});
}});
}});
}};
Динамические прокси (добавлены в 1.3) позволяют вам определять новый тип во время выполнения, который соответствует интерфейсу. Это пригодилось удивительное количество раз.
окончательная инициализация может быть отложена.
Это гарантирует, что даже при сложном потоке логики возвращаемые значения всегда устанавливаются. Слишком легко пропустить случай и вернуть ноль случайно. Это не делает возврат нуля невозможным, просто очевидно, что это специально:
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;
}
Я думаю, что еще одна «упущенная из виду» особенность Java - сама JVM. Это, вероятно, лучшая доступная виртуальная машина. И он поддерживает множество интересных и полезных языков (Jython, JRuby, Scala, Groovy). Все эти языки могут легко и без проблем сотрудничать.
Если вы разрабатываете новый язык (как в случае с scala), вы сразу же получаете все имеющиеся библиотеки, и поэтому ваш язык «полезен» с самого начала.
Все эти языки используют оптимизацию HotSpot. ВМ очень хорошо контролирует и отлаживается.
Вы можете определить анонимный подкласс и напрямую вызвать метод для него, даже если он не реализует интерфейсы.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
start()
), фактически не определен в подклассе ...
asList в java.util.Arrays
позволяет получить хорошую комбинацию varargs, универсальных методов и автобокса:
List<Integer> ints = Arrays.asList(1,2,3);
Arrays.asList
Имеет необычную особенность , что вы можете set()
элементы , но не add()
или remove()
. Поэтому я обычно оборачиваю его в a new ArrayList(...)
или в a Collections.unmodifiableList(...)
, в зависимости от того, хочу ли я изменить список или нет.
Использование этого ключевого слова для доступа к полям / методам, содержащим класс из внутреннего класса. В следующем, довольно надуманном примере мы хотим использовать поле 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;
}
}
MyActivity.this
.
Не совсем особенность, но забавный трюк, который я недавно обнаружил на какой-то веб-странице:
class Example
{
public static void main(String[] args)
{
System.out.println("Hello World!");
http://Phi.Lho.free.fr
System.exit(0);
}
}
является допустимой программой Java (хотя она генерирует предупреждение). Если вы не понимаете почему, посмотрите ответ Грегори! ;-) Ну, подсветка синтаксиса здесь тоже подсказывает!
Это не совсем «скрытые функции» и не очень полезные, но в некоторых случаях может быть чрезвычайно интересным:
класс 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);
}
};
}
При работе в Swing мне нравится скрытый Ctrl- Shift-F1 функция.
Он сбрасывает дерево компонентов текущего окна.
(Предполагая, что вы не связали это нажатие клавиши с чем-то другим.)
Каждый файл класса начинается с шестнадцатеричного значения 0xCAFEBABE чтобы идентифицировать его как действительный байт-код JVM.
( Объяснение )
Я голосую за java.util.concurrent с его параллельными коллекциями и гибкими исполнителями, позволяющими среди прочих пулов потоков, запланированных и скоординированных задач. DelayQueue - мой личный фаворит, где элементы становятся доступными после указанной задержки.
java.util.Timer и TimerTask можно смело положить на отдых.
Кроме того, не совсем скрыто, но в другой упаковке, чем другие классы, связанные с датой и временем. java.util.concurrent.TimeUnit полезен при преобразовании между наносекундами, микросекундами, миллисекундами и секундами.
Он читается намного лучше, чем обычный someValue * 1000 или someValue / 1000.
CountDownLatch
и CyclicBarrier
- так полезен!
Ключевое слово assert на уровне языка .
Не совсем часть языка Java, но дизассемблер javap, поставляемый с Sun JDK, широко не известен и не используется.
Добавление конструкции для каждого цикла в 1.5. Я <3 это.
// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
System.out.println(foo.toString());
}
И может использоваться во вложенных экземплярах:
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
Конструкция for-each также применима к массивам, где она скрывает переменную индекса, а не итератор. Следующий метод возвращает сумму значений в массиве int:
// Returns the sum of the elements of a
int sum(int[] a) {
int result = 0;
for (int i : a)
result += i;
return result;
}
i
здесь очень запутанно, так как большинство людей ожидают, что я буду индексом, а не элементом массива.
лично я обнаружил java.lang.Void
очень поздно - улучшает читаемость кода в сочетании с обобщениями, напримерCallable<Void>