суббота, 11 августа 2012 г.

Сколько объектов в коллекции?

Что выведет программа?

public class Animal {
    private final String type;
    Animal(String type) {
       this.type = type; 
    }
    
    public boolean equals(Animal animal) {
        return type.equals(animal.type);
    }
    
    public int hashCode() {
        return type.hashCode();
    }

    
    public static void main(String[] args) {
        Set set = new HashSet();
        set.add(new Animal("Dog"));
        set.add(new Animal("Cat"));
        set.add(new Animal("Cat"));
        System.out.println(set.size());
    }
}

Ответ

3
Метод equals должен принимать объекты типа Object, а у нас - Animal. Из-за этого не произошло перезаписи метода и использовался метод equals класса Object. Что бы такого не просходило, надо всегда использовать аннотацию @Override в тех местах, где мы хотим переопределить метод.

пятница, 10 августа 2012 г.

Конкатенация

Что выведет программа?
System.out.println(1 + 2 + 3 + "" + 4 + 5 + 6);

Ответ

6456
Т.к. операции выполняются слева направо, то сначала выполнится сложение, затем конкатенация

суббота, 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
 */

четверг, 29 марта 2012 г.

Паттерн Комманда(Command). Пример кода

public class Steps {
    public void goSouth() {
        System.out.println("step to south");
    }
    
    public void goNorth() {
        System.out.println("step to north");
    }
    
    public void goEast() {
        System.out.println("step to east");
    }
    
    public void goWest() {
        System.out.println("step to west");
    }
}

public abstract class StepsCommand implements Command {
    protected Steps steps = new Steps();
}

public interface Command {
    void execute();
}

public class GoEastCommand extends StepsCommand {
    @Override
    public void execute() {
        steps.goEast();
    }
}

public class GoNorthCommand extends StepsCommand {
    @Override
    public void execute() {
        steps.goNorth();
    }
}

public class GoSouthCommand extends StepsCommand {
    @Override
    public void execute() {
        steps.goSouth();
    }
}

public class GoWestCommand extends StepsCommand {
    @Override
    public void execute() {
        steps.goWest();
    }
}

public class Navigator {
    private final List<StepsCommand> steps = new LinkedList<>();
    private final List<StepsCommand> path = new LinkedList<>();
    
    public Navigator registerStep(StepsCommand step) {
        steps.add(step);
        return this;
    }
    
    public void go() {
        for(StepsCommand step : steps) {
            step.execute();
            ((LinkedList)path).addFirst(step);
        }
        steps.clear();
    }
    
    public void goBack() {
        for(StepsCommand step : path) {
            step.execute();
        }
        path.clear();
    }
}

public class Client {
    public static void main(String[] args) {
        Navigator navigator = 
            new Navigator().registerStep(new GoEastCommand())
                           .registerStep(new GoNorthCommand())
                           .registerStep(new GoNorthCommand())
                           .registerStep(new GoSouthCommand());
        System.out.println("go");
        navigator.go();
        System.out.println("go back");
        navigator.goBack();
    }
}
/**
 * Output:
 * go
 * step to east
 * step to north
 * step to north
 * step to south
 * go back
 * step to south
 * step to north
 * step to north
 * step to east
 */

среда, 14 марта 2012 г.

Паттерн Цепочка обязанностей(Chain of responsibility). Пример кода

public class HouseProject {
    private final Set steps = new HashSet();
    
    public HouseProject(Steps... steps) {
        this.steps.addAll(Arrays.asList(steps));
    }
    
    public enum Steps {
        CREATE_BASEMENT,
        ADD_FLOOR,
        CREATE_ROOF,
        BUILD_FENCE
    }
    public Set getSteps() {
        return steps;
    }
}

public abstract class Builder {
    protected Builder nextBuilder;
    private final HouseProject.Steps step;
    
    public Builder(HouseProject.Steps step) {
        this.step = step;
    }
    
    public abstract void buildImpl();
    
    public void build(HouseProject project) {
        if (project.getSteps().contains(step)) {
            buildImpl();
        }
        if (nextBuilder != null) {
            nextBuilder.build(project);
        }
    }
    
    public Builder setNext(Builder builder) {
        nextBuilder = builder;
        return builder;
    }
}

public class BasementBuilder extends Builder {
    public BasementBuilder() {
        super(HouseProject.Steps.CREATE_BASEMENT);
    }

    @Override
    public void buildImpl() {
        System.out.println("Building basement");
    }
}

public class FloorBuilder extends Builder {
    public FloorBuilder() {
        super(HouseProject.Steps.ADD_FLOOR);
    }

    @Override
    public void buildImpl() {
        System.out.println("Building floor");
    }
}

public class RoofBuilder extends Builder {
    public RoofBuilder() {
        super(HouseProject.Steps.CREATE_ROOF);
    }

    @Override
    public void buildImpl() {
        System.out.println("Building roof");
    }
}

public class FecneBuilder extends Builder {
    public FecneBuilder() {
        super(HouseProject.Steps.BUILD_FENCE);
    }

    @Override
    public void buildImpl() {
        System.out.println("Building fence");
    }
}

public class Client {
    public static void main(String[] args) {
        Builder firstBuilder, lastBuilder;
        firstBuilder = lastBuilder = new BasementBuilder();
        lastBuilder = lastBuilder.setNext(new FloorBuilder())
                                 .setNext(new RoofBuilder())
                                 .setNext(new FecneBuilder());
        
        HouseProject hp = new HouseProject(
            HouseProject.Steps.CREATE_BASEMENT,
            HouseProject.Steps.ADD_FLOOR,
            HouseProject.Steps.CREATE_ROOF
        );
        
        firstBuilder.build(hp);
    }
}

/**
 * Output:
 * Building basement
 * Building floor
 * Building roof
 */

среда, 22 февраля 2012 г.

Паттерн Прокси(Proxy). Пример кода

public interface Image {
    public String get(String imgName);
}

public class LargeImage implements Image {
    @Override
    public String get(String imgName) {
        System.out.println("some expensive operation for loading image");
        return String.format("image with name \"%s\"", imgName);
    }
}

public class ImageProxy implements Image {
    
    private Image realImage = new LargeImage();
    private Map loadedImages = new HashMap();
    
    @Override
    public String get(String imgName) {
        if (loadedImages.get(imgName) != null) {
            return loadedImages.get(imgName);
        } else {
            String image = realImage.get(imgName);
            loadedImages.put(imgName, image);
            return image;
        }
    }
}

public class ImagesTester {
    public static void main(String[] args) {
        Image image1 = new ImageProxy();
        Image image2 = new LargeImage();
        System.out.println(image1.get("Flowers.jpg"));
        System.out.println(image1.get("Flowers.jpg"));
        System.out.println(image1.get("Flowers.jpg"));
        
        System.out.println(image2.get("Sky.jpg"));
        System.out.println(image2.get("Sky.jpg"));
    }
}
/**
 * Output:
 * some expensive operation for loading image
 * image with name "Flowers.jpg"
 * image with name "Flowers.jpg"
 * image with name "Flowers.jpg"
 * some expensive operation for loading image
 * image with name "Sky.jpg"
 * some expensive operation for loading image
 * image with name "Sky.jpg"
 */

суббота, 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 г.

Замечательный класс java.util.prefs.Preferences

Класс java.util.prefs.Preferences позволяет сохранять небольшие объемы данных, которые затем можно получать при последующих запусках программы. Возможно, будет полезно его использовать в некоторых случаях вместо сериализации объектов.


public class PreferencesTest {
    private static Preferences pref = 
        Preferences.userNodeForPackage(PreferencesTest.class);
    
    public PreferencesTest() {
        int launchesCount = pref.getInt("launchesCount", 0);
        pref.putInt("launchesCount", ++launchesCount);
        System.out.format(
            "Hello, %s! Your app launches count is %d%n", 
            getName(), 
            launchesCount
        );
    }
    
    public static void main(String[] args) {
        PreferencesTest prefTest1 = new PreferencesTest();
        prefTest1.setName("Sub Zero");
        new PreferencesTest();
        new PreferencesTest();
    }
    
    public void setName(String name) {
        pref.put("name", name);
    }
    
    public String getName() {
        return pref.get("name", "Guest");
    }
}
/**
 * Hello, Guest! Your app launches count is 1
 * Hello, Sub Zero! Your app launches count is 2
 * Hello, Sub Zero! Your app launches count is 3
 */

@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();