Показаны сообщения с ярлыком заметки. Показать все сообщения
Показаны сообщения с ярлыком заметки. Показать все сообщения

суббота, 2 июня 2012 г.

Объявление констант

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

package com.effectivejava.science;

public class PhysicalConstants {
    private PhysicalConstants() { } // Prevents instantiation
    public static final double AVOGADROS_NUMBER = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS = 9.10938188e-31;
}


// Use of static import to avoid qualifying constants
import static com.effectivejava.science.PhysicalConstants.*;

public class Test {
    double atoms(double mols) {
        return AVOGADROS_NUMBER * mols;
    }
    // Many more uses of PhysicalConstants justify static import
}



воскресенье, 29 апреля 2012 г.

Пример написания hashCode и equals


public class HashCodeTest {
    boolean boolVar = true;
    byte byteVar = 123;
    short shortVar = 12345;
    char charVar = 12;
    int intVar = 1234567890;
    long longVar = 1234567890123456789L;
    float floatVar = 12345.0F;
    double doubleVar = 123456789012.8D;
    int[] arrayVar = {1,2,3,4,5,6,7};
    String objectVar = "String";
    Object nullVar = null;
    
    public static void main(String[] args) {
        HashCodeTest hct = new HashCodeTest();
        HashCodeTest hct2 = new HashCodeTest();
        System.out.format("%s%n%s", hct.hashCode(), hct.equals(hct2));
    }
    
    @Override
    public int hashCode() {
        int result = 17;
        //compute int hash-code for every field
        result = 31 * result + (boolVar?1:0);
        result = 31 * result + (int) byteVar;
        result = 31 * result + (int) shortVar;
        result = 31 * result + (int) charVar;
        result = 31 * result + intVar;
        result = 31 * result + (int) (longVar ^ (longVar >>> 32));
        result = 31 * result + Float.floatToIntBits(floatVar);
        result = 31 * result + (int) (Double.doubleToLongBits(doubleVar) ^ 
            (Double.doubleToLongBits(doubleVar) >>> 32));
        result = 31 * result + 0; //for nullVar
        result = 31 * result + objectVar.hashCode();
        result = 31 * result + Arrays.hashCode(arrayVar);
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj instanceof HashCodeTest) {
            HashCodeTest hct = (HashCodeTest) obj;
            return boolVar == hct.boolVar && 
                   byteVar == hct.byteVar && 
                   shortVar == hct.shortVar && 
                   charVar == hct.charVar && 
                   intVar == hct.intVar && 
                   longVar == hct.longVar && 
                   floatVar ==  hct.floatVar && 
                   doubleVar == hct.doubleVar && 
                   Arrays.equals(arrayVar, hct.arrayVar) && 
                   objectVar.equals(hct.objectVar);
        }
        return false;
    }
}

/**
 * Output: 
 * -1172080207
 * true
 */

суббота, 18 февраля 2012 г.

Особенность использования блока finally

Блок finally исполняется даже после операторов break, continue и return. Но если внутри блока finally выскочит исключение или будет вызвана команда return, всё что будет после в этом блоке не выполнится:

try {
    throw new Exception("Some exception");
} catch (Exception e) {
    System.out.println(e.getMessage());
} finally {
    String t = null;
    t.contains("string");
    System.out.println("Never printed");
}
/**
 * Output:
 * Some exception
 * Exception in thread "main" java.lang.NullPointerException
 * at test.TestFinally.main(TestFinally.java:18)
 */

вторник, 31 января 2012 г.

Опасность при вызове методов из конструктора

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

public class Parent {
    Parent() {
        test();
    }
    
    public static void main(String[] args) {
        new Child();
    }
 
    protected void test() {
     System.out.println("Hello from Parent");
    }
}

class Child extends Parent {
    private final String someString;
    Child() {
        someString = "some Text";
    }
    protected void test() {
        System.out.println("Hello from Child");
        System.out.println(someString);
    }
}
/**
 * Output:
 * Hello from Child
 * null
 */

четверг, 8 декабря 2011 г.

Wrapper pools

В Java для более эффективного использования памяти используются пулы для хранения одних и тех же значений. Например, если создать две строковые переменные одинакового содержания без использования ключевого слова new, то при создании второй переменной ей будет присвоена ссылка на первую. Тоже касается, например, объектов Integer, но только для значений от -128 до 127. Но строки, созданные во время выполнения не будут являться одним объектом, за искобчением случая использования метода intern()


public class StringTest {
    public static final void main(String[] args) {
        String a = "Test string";
        String b = "Test string";
        String c = new String("Test string");
        
        String d = "Test ";
        String e = "string";
        
        System.out.format(
            "%s %s %s %s",
            a == b, a == c, a == (d + e), a == (d + e).intern()
        );
    }
}
/**
 * Output: true false false true
 */

среда, 7 декабря 2011 г.

Финализация потока-демона

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

public class DeamonTest implements Runnable {   
    public void run() {
        try {
            System.out.println("Trying");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        } finally {
            System.out.println("Never prints");
        }
    }
    
    public static void main(String[] args) {
        Thread t = new Thread(new DeamonTest());
        t.setDaemon(true);
        t.start();
    }
}
/**
 * Output: Trying
 */

Локальные классы и их модификаторы

Локальные классы не могут быть объявлены как public/private/protected/static, т.к. эти модификаторы предназначены только для членов класса

вторник, 6 декабря 2011 г.

Немного про сериализацию

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

Значения статических полей не сохраняются при сериализации.

Если в иерархии объектов, при их сериализации, попадется объект - не serializable - выскочит exception.

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

Method overloading

При передаче параметра одному из перегруженных методов всегда выбирается наиболее специфичный, например:

public class Overload {
      public void method(Object o) {
        System.out.println("Object");
      }
      public void method(java.io.FileNotFoundException f) {
        System.out.println("FileNotFoundException");
      }
      public void method(java.io.IOException i) {
        System.out.println("IOException");
      }
      public static void main(String args[]) {
        Overload test = new Overload();
        test.method(null);
      }
}
/**
 * Output: FileNotFoundException
 */
Если среди перегруженных методов есть те, которые принимают объекты, находящиеся на одном уровне иерархии, код не скомпилируется:

public class Overload {
    public void method(Object o) {
        System.out.println("Object");
      }
      public void method(String s) {
        System.out.println("String");
      }
      public void method(StringBuffer sb) {
        System.out.println("StringBuffer");
      }
      public static void main(String args[]) {
        Overload test = new Overload();
        test.method(null); //The method method(Object) is ambiguous for the type Overload
      }
}
По мотивам http://habrahabr.ru/blogs/java/111189/

понедельник, 5 декабря 2011 г.

Исключения и переопределение метода

Исключения и переопределение метода — 1

Что будет выведено в результате выполнения этого кода?

class A {
    public void print() throws Exception {
        throw new Exception();
    }
}

class B extends A {
    public void print() {
        System.out.println("B");
    }
}

public class Main {

    public static final void main(String[] args) {
        B b = new B();
        b.print();
    }

}

1. B
2. Ничего
3. Ошибка компиляции
4. Exception

Ответ:
Переопределяющий метод не должен бросать новое или более широкое по классу исключение. Не бросать его вообще он может. Так что код скомпилируется и выведет B.

Исключения и переопределение метода — 2

Что будет выведено в результате выполнения этого кода?

class A {
    public void print() throws Exception {
        throw new Exception();
    }
}

class B extends A {
    public void print() {
        System.out.println("B");
    }
}

public class Main {

    public static final void main(String[] args) {
        A a = new B();
        a.print();
    } 

}

1. B
2. Ничего
3. Ошибка компиляции
4. Exception

Ответ:
3. Ошибка компиляции.
Так как мы в классе A объявлено исключение, а в main(...) мы его не обрабатываем. Тип возвращаемого значения (который может быть не таким, как в суперклассе, ведь есть covariant return) и выбрасываемые исключения проверяются компилятором по типу ссылки.

Источник: http://habrahabr.ru/blogs/java/131198/

instanceof

Что будет выведено в результате выполнения этого кода?

class A {
}

class B extends A {
}

class C extends B {
}

class D {
}

public class Main {

    public static final void main(String[] args)  {
        B b = new C();
        A a = new C();
        D d = new D();
        System.out.println(b instanceof A);
        System.out.println(a instanceof B);
        System.out.println(d instanceof C);
    }
}
1. true true false
2. true false false
3. Ошибка компиляции

Ответ:
3. Ошибка компиляции. Так произойдет, потому что D и C находятся на разных ветках иерархии и не приводимы друг к другу.

Источник: http://habrahabr.ru/blogs/java/131198/

пятница, 2 декабря 2011 г.

@Override

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

Правильно определять обертки примитивных типов


//медленно
Integer i = new Integer(100);
Long l = new Long(100);
String s = new String("A");
String s1 = 8 + "";

//быстро
Integer i = Integer.valueOf(100);
Long l = 100L; //это тоже самое что Long.valueOf(100L);
String s = "A";
String s1 = String.valueOf(8);

четверг, 1 декабря 2011 г.

Всегда возвращать пустые коллекции и массивы, вместо null.

Это сэкономит время на дальнейшей проверке значения на null в местах использования.
Для коллекций существуют специальные методы:
Collections.emptyList();
Collections.emptyMap();
Collections.emptySet();

Статические поля родителей являются общими для наследников


class T1 extends T {}

class T2 extends T {}

class T {
    public static int i;
}

public class Test {
    public static void main(String[] args) {
        T1.i = 5;
        T2.i = 3;
        System.out.format("%d = %d", T1.i, T2.i);
    }
}

/**
 * Output: 3 = 3
 */

Избегать конкатенации строк оператором +

Избегать конкатенации строк оператором +. При каждом использовании данного оператора создается новый объект.


Long l1 = System.currentTimeMillis();
String test = new String();
for (int i = 0; i < 100000; i++) {
    test += "d";
}
System.out.println(System.currentTimeMillis()-l1);

Long l2 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
    sb.append("d");
}
System.out.println(System.currentTimeMillis()-l2);
/**
 * Output:
 * 10728
 * 10
 */

Использование нестатических блоков инициализации

При помощи нестатических блоков инициализации можно элегантно инициализировать коллекцию:
Map map = new HashMap() {{
    put("собака",  "барбос");
    put("попугай", "кеша");
    put("кошка",   "мурка");
}};

Сериализация

При десериализации не вызывается конструктор дессириализуемого класса, но если его родители не реализуют интерфейс Serializable, то у них вызывается конструктор по умолчанию.

java.io.NotSerializableException выбрасываться не будет в случае B b = null, т.к. объект не был инициализирован.


public class Test {
    public static void main(String[] args) throws FileNotFoundException, 
    IOException, ClassNotFoundException {
        ObjectOutputStream out = 
            new ObjectOutputStream(new FileOutputStream("testfile"));
        out.writeObject(new C(1));
        
        ObjectInputStream in = 
            new ObjectInputStream(new FileInputStream("testfile"));
        in.readObject();
    }
}

class B {
    public B() {
        System.out.print("B");
    }
    public B(int i) {
        System.out.print("1");
    }
}

class C extends B implements Serializable {
    B b = null;
    public C() {
        System.out.print("C");
    }
    public C(int i) {
        super(i);
        System.out.print("2");
    }
}
/**
 * Output: 12B
 */