Прочитавши приховані особливості C #, я задумався, які існують приховані особливості Java?
Прочитавши приховані особливості C #, я задумався, які існують приховані особливості Java?
Відповіді:
Подвійна брекет-ініціалізація мене здивувала кілька місяців тому, коли я вперше виявив її, ніколи раніше про неї не чув.
Зазвичай ThreadLocals не настільки широко відомий як спосіб зберігання стану в потоці.
Оскільки JDK 1.5 Java має надзвичайно добре реалізовані та надійні інструменти одночасності, крім простого блокування, вони живуть у java.util.concurrent, а особливо цікавим прикладом є java.util.concurrent.atomic підпакет, який містить безпечні для потоків примітиви, які реалізують порівняння -і операція підкачки та може відображати фактичні підтримувані апаратними версіями цих операцій.
Дисперсія параметрів спільного з'єднання в типі:
public class Baz<T extends Foo & Bar> {}
Наприклад, якщо ви хочете взяти параметр, який є "Порівняним" і "Колекція":
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);
}
Цей надуманий метод повертає істину, якщо дві задані колекції рівні або якщо одна з них містить даний елемент, інакше помилковий. Слід зазначити, що на аргументах b1 і b2 можна викликати методи як Comprable, так і Collection.
Днями мене здивували ініціалізатори екземплярів. Я видаляв декілька методів, складених кодом, і в результаті створив кілька ініціалізаторів екземплярів:
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.
Класифіковані підказки з 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
.
Передача контролю в остаточному блоці викидає будь-який виняток. Наступний код не кидає 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
Ніколи не бачив, щоб хтось згадував про те, що він був реалізований таким чином, що перевірка наявності null не потрібна.
Замість:
if( null != aObject && aObject instanceof String )
{
...
}
просто використовуйте:
if( aObject instanceof String )
{
...
}
free
ing або delete
ing у 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 () дасть помилку компіляції.
Ви можете використовувати enums для реалізації інтерфейсу.
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 / console window
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. Це, мабуть, найкращий доступний VM. І він підтримує безліч цікавих і корисних мов (Jython, JRuby, Scala, Groovy). Усі ці мови можуть легко та безперешкодно співпрацювати.
Якщо ви розробляєте нову мову (як, наприклад, у шкалі шкали), у вас одразу є доступні всі наявні бібліотеки, тому ваша мова є «корисною» з самого початку.
Усі ці мови використовують оптимізацію HotSpot. VM дуже добре контролює та налагоджує.
Ви можете визначити анонімний підклас і безпосередньо викликати метод на ньому, навіть якщо він не реалізує інтерфейсів.
new Object() {
void foo(String s) {
System.out.println(s);
}
}.foo("Hello");
start()
), фактично не визначений у підкласі ...
AsList метод java.util.Arrays
дозволяє гарне поєднання, загальних списків параметрів методів і Autoboxing:
List<Integer> ints = Arrays.asList(1,2,3);
Arrays.asList
Має незвичайну особливість , що ви можете set()
елементи , але не add()
або remove()
. Тому я зазвичай загортаю його в new ArrayList(...)
або в Collections.unmodifiableList(...)
, залежно від того, хочу я, щоб список мінявся чи ні.
Використання цього ключового слова для доступу до полів / методів, що містять клас із внутрішнього класу. Нижче, досить надуманий приклад, ми хочемо використовувати поле sortAscending контейнера класу з анонімного внутрішнього класу. Використання ContainerClass.this.sortAscending замість цього.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функція.
Він скидає компонентне дерево поточного вікна.
(Припустимо, що ви не пов’язали цей натискання клавіші з чимось іншим.)
Я голосую за java.util.concurrent зі своїми одночасними колекціями та гнучкими виконавцями, які дозволяють серед інших пулів потоків, запланованих завдань та узгоджених завдань. DelayQueue - мій особистий фаворит, де елементи стають доступними після зазначеної затримки.
java.util.Timer і TimerTask можуть спокійно перепочити.
Також не точно приховано, але в іншому пакеті, ніж інші класи, пов’язані з датою та часом. java.util.concurrent.TimeUnit корисний при перетворенні між наносекундами, мікросекундами, мілісекундами та секундами.
Він читає набагато краще, ніж звичайний деякийValue * 1000 або деякийValue / 1000.
CountDownLatch
і CyclicBarrier
- такий корисний!
Ключове слово затвердження на рівні мови .
Насправді не є частиною мови Java, але розбірник javap, який поставляється з JDK Sun, широко не відомий і не використовується.
Додавання конструкції для кожного циклу в 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 для кожного також застосовна для масивів, де вона приховує змінну індексу, а не ітератор. Наступний метод повертає суму значень у масиві 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>