• ,

Вопрос по добавлению элементов в множество Set

Здравствуйте!

Недавно писал программу решения одной задачи в java, в ней в цикле шел перебор возможных решений. Решение представляет собой массив известной длины. Создал множество таких массивов solutions, в которое в цикле добавлял подходящие решения (они были в массиве sol):

solutions.add(sol);

Первое найденное решение добавлялось, а вот последующие уже нет. Первая мысль — решение повторяется, но нет, они все оригинальные… Решения стали добавляется после добавления процедуры clone():

solutions.add(sol.clone());

Почему первый вариант команды не добавлял элементы, а второй — добавлял?
  • ,

Как пользоваться CopyOnWriteArraySet в Java с примером (перевод)

CopyOnWriteArraySet это младший брат класса CopyOnWriteArrayList. Это специализированный набор классов, добавленных в JDK 1.5 вместе с их более популярным двоюродным братом ConcurrentHashMap. Они являются частью concurrent collection framework и расположены в пакете java.util.concurrent.

CopyOnWriteArraySet лучше всего подходит для read-only коллекций, размер которых достаточно мал, чтобы их скопировать, если произойдут некоторые изменяющие операции. Например, вы можете использовать CopyOnWriteArraySet для хранения объекта при запуске приложения, и дать множеству других потоков доступ к этому объекту на протяжении жизненного цикла приложения. Если новое состояние или объект приходят в течение этого времени, он также может быть добавлен в этот Set, со стоимостью создания нового массива.

Одна из самых важных вещей, которую стоит знать о CopyOnWriteArraySet это то, что он реализован при помощи CopyOnWriteArrayList. Это означает, что CopyOnWriteArraySet также разделяет все основные свойства CopyOnWriteArrayList. Еще одна важная вещь, которую стоит запомнить: итераторы этого класса коллекции не поддерживают операцию remove(). Попытка удалить элемент во время итерирования приведет к выбросу UnsupportedOperationException. Это сделано чтобы гарантировать скорость во время обхода. Обход этой реализации Set, используя итератор, осуществляется достаточно быстро, и во время него исключены вмешательства других потоков. В своей работе итераторы опираются на моментальный снимок массива, который был сделан во время создания итератора.

Короче говоря, используйте CopyOnWriteArraySet если set достаточно мал, чтобы копировать его при добавлении, задании значения или удалении объектов, и основной целью является чтение обновляемых от случая к случаю данных. Кроме того, если вы хотите удалить элементы во время итерации, не используйте эту реализацию, потому что ее итератор не поддерживает remove(), и бросает java.lang.UnsupportedOperationException, как показано ниже:


[RAJ] Event received : FOUR 
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(Unknown Source)
    at Publisher.notifySubs(HelloHP.java:43)
    at HelloHP.main(HelloHP.java:23)


CopyOnWriteArraySet пример на Java

Вот готовая программа на Java показывающая, как использовать CopyOnWriteArraySet. В нашем примере мы использовали шаблон проектирования «Издатель-подписчик» (англ. publisher-subscriber pattern), чтобы продемонстрировать его использование. Большинство подписчиков подписаны во время пуска приложения и главной задачей издателя является их перебор и уведомление о каких-либо обновлениях. Время от времени может случаться добавление и удаление подписчика. Так как нам нужен быстрый обход, CopyOnWriteArraySet является хорошим выбором, особенно в многопоточной среде, где один поток может добавить абонента, а другой поток обрабатывает обновления.


import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Java program to demonstrate how to use CopyOnWriteArraySet in Java. Remember,
 * CopyOnWriteArraySet doesn't support remove() operation.
 *
 * @author Javin Paul
 */
public class CopyOnWriteArraySetDemo{

    public static void main(String args[]) {
        Publisher cricNext = new Publisher();

        SubScriber raj = new SubScriber("RAJ");
        SubScriber adom = new SubScriber("ADOM");

        cricNext.addSubscriber(raj);
        cricNext.addSubscriber(adom);

        cricNext.notifySubs("FOUR");
        cricNext.notifySubs("SIX");

    }

}

class Publisher {

    private CopyOnWriteArraySet setOfSubs = new CopyOnWriteArraySet();

    public void addSubscriber(SubScriber sub) {
        setOfSubs.add(sub);
    }

    public void notifySubs(String score) {
        Iterator itr = setOfSubs.iterator();
        while (itr.hasNext()) {
            SubScriber sub = itr.next();
            sub.receive(score);

            //itr.remove(); // not allowed, throws UnsupportedOperationException
        }
    }
}

class SubScriber {

    private String _name;

    public SubScriber(String name) {
        this._name = name;
    }

    public void receive(String score) {
        System.out.printf("[%s] Event received : %s %n", _name, score);
    }
}


Output:
[RAJ] Event received : FOUR 
[ADOM] Event received : FOUR 
[RAJ] Event received : SIX
[ADOM]Event received : SIX


Что нужно запомнить

CopyOnWriteArraySet реализует интерфейсы Collection и Set, а также, добавленный в JDK 1.5, вместе с другой специальной реализацией Set'а, EnumSet. Это также Set, который использует внутренний CopyOnWriteArrayList для всех своих операций. Таким образом, он разделяет те же основные свойства этого класса. Так как это не SortedSet, порядок элементов не гарантируется в течение итерации.

1. CopyOnWriteArraySet лучше всего подходит для приложений, в которых:
  • Размеры Set'ов, как правило остаются небольшими.
  • Операции read-only значительно превосходят операции, изменяющие объекты.
  • Вы должны предотвратить помехи между потоками во время обхода Set'а.

2. Еще одним преимуществом CopyOnWriteArraySet является потокобезопасность. Эта коллекция поддерживает параллелизм.
3. Мутативные операции (добавление, изменение, удаление и т.д.) являются дорогостоящими, так как они, как правило, требуют копирования всего базового массива.
4. Итераторы не поддерживают мутативную операцию удаления.
5. Обход используя итератор достаточно быстр и во время него исключены вмешательства других потоков. В своей работе итераторы опираются на моментальный снимок массива, который был сделан во время создания итератора.

На этом все об использовании CopyOnWriteArraySet в Java. Как я сказал, он является младшим братом CopyOnWriteArrayList. Так что если вы понимаете хотя бы один из них, то сможете использовать и другой. Единственное отличие в том, что один является List'ом а другой Set'ом, таким образом это влечет за собой унаследование всех отличий между этими структурами данных в Java. Например, в List важен порядок расположения элементов, и он может содержать дубликаты. В то время как Set является неупорядоченным, но не позволяет дублирование объектов.

Всегда помните, что CopyOnWriteArraySet это специализированный Collection класс. Его стоит использовать только когда условия являются благоприятными. В любом другом случае можно пользоваться реализациями общего назначения. Например, HashSet, LinkedHashSet или синхронизированными классами коллекций.

Оригинал статьи
  • ,

level09.lesson11.home09 программа не компилируется на сервере

package com.javarush.test.level09.lesson11.home09;
public class Solution
{
    public static void main(String[] args)
    {
        Map<String, Cat> map = createMap();
        Set<Cat> set = convertMapToSet(map);
        printCatSet(set);
    }

    public static Map<String, Cat> createMap()
    {
        Map<String, Cat> map = new HashMap<String, Cat>();
//        map.put("Vaska", new Cat("Vaska"));
//        map.put("Maska", new Cat("Maska"));
//        map.put("Koshka", new Cat("Koshka"));
//        map.put("Toha", new Cat("Toha"));
//        map.put("Riji", new Cat("Riji"));
//        map.put("Detka", new Cat("Detka"));
//        map.put("Milii", new Cat("Milii"));
//        map.put("Ben", new Cat("Ben"));
//        map.put("Timon", new Cat("Timon"));
//        map.put("Tom", new Cat("Tom"));
        String catName = "Murzik";
        for (int i = 0; i < 10; i++)
        {

            map.put(catName + i,new Cat(catName + i));
        }//Напишите тут ваш код
        return map;
    }

    public static Set<Cat> convertMapToSet(Map<String, Cat> map)
    {
        Set<Cat> set = new HashSet<Cat>(map.values());
//        Iterator<Map.Entry<String, Cat>> iterator = map.entrySet().iterator();
//        while (iterator.hasNext()){
//            Map.Entry<String, Cat> pair = iterator.next();
//            String s = pair.getKey();
//        }
//        for (Map.Entry<String, Cat> pair : map.entrySet())
//        {
//            //Cat s = pair.getValue();
//            set.add(pair.getValue());
//        }//Напишите тут ваш код
        return set;
    }

    public static void printCatSet(Set<Cat> set)
    {
        for (Cat cat:set)
        {
            System.out.println(cat);
        }
    }

    public static class Cat
    {
        private String name;

        public Cat(String name)
        {
            this.name = name;
        }

        public String toString()
        {
            return "Cat "+this.name;
        }
    }


}

Подскажите пожалуйста.(интерфейсы)

Не могу понять почему не компилируется последняя строчка.
Интерфейс реализует одного работника(Employee), у которого есть менеджер.
Задача состоит в том, чтобы создать цепочку работников (Employee-->Employee.manager-->> topmanager).
Я не уверен в том, что я правильно реализовал метод getTopManager.
Компилятор говорит вот что:

Exception in thread «main» java.lang.NullPointerException
Hasan
at exp1.Check.main(forexp1.java:89)
Hasan
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Hasan
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Собственно код:
package exp1;

/**
* Created by Хасан on 06.07.2014.
*/
interface Employee{
public void setName(String name);
public String getName();
public void setManager(Employee manager);
public String getManagerName();
public Employee getTopManager();
}

class Employeeimpl implements Employee {
String name;
Employeeimpl manager;

Employeeimpl(String name){
this.name = name;
}

Employeeimpl(){
}

Employeeimpl(String name, Employeeimpl manager){
this.name = name;
this.manager = manager;
}

@Override
public void setName(String name) {
this.name = name;
}

@Override
public String getName() {
return this.name;
}

@Override
public void setManager(Employee manager) {
Employeeimpl managerimpl1 = (Employeeimpl) manager;
this.manager = managerimpl1;
}

@Override
public String getManagerName() {
return this.manager.name;
}

@Override
public Employee getTopManager() {
Employeeimpl employeeimpl = (Employeeimpl) this;
if (employeeimpl.manager == null)
return this;
else {
Employeeimpl highermanager = employeeimpl.manager.manager;
while (true) {
if (highermanager == null)
break;
else
highermanager = highermanager.manager;
}
return highermanager;
}

}
}

class Check{
public static void main(String[]args){
Employeeimpl hasan=new Employeeimpl();
Employeeimpl stive = new Employeeimpl();
Employeeimpl john = new Employeeimpl();
hasan.setManager(null);
stive.setManager(hasan);
john.setManager(stive);

hasan.setName(«Hasan»);
stive.setName(«Stive»);
john.setName(«John»);

System.out.println(hasan.getName());
System.out.println(stive.getManagerName());
System.out.println(john.manager.getManagerName());
Employee topmanager = new Employeeimpl();
topmanager = john.getTopManager();
System.out.println(topmanager.getName());

}
}
  • ,

level08.lesson08.task05 Разбор полетов

Со всех задач, решенных на JavaRush, застрял именно на этой конкретно, и понял, что остались не понятные моменты по Set, Map, Iterator. Прошу помощи знающих :)

/* Удалить людей, имеющих одинаковые имена
Создать словарь (Map<String, String>) занести в него десять записей по принципу «фамилия» - «имя».
Удалить людей, имеющих одинаковые имена.
*/
public class Solution
{
    public static HashMap<String, String> createMap()
    {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("Сидоров", "Сидор");
        map.put("Федоров", "Федя");
        map.put("Николаев", "Коляба");
        map.put("Егоров", "Жорик");
        map.put("Светка", "Чветка");
        map.put("Костин", "Костямба");
        map.put("Киров", "Кирюха");
        map.put("Стоянова", "Стоя");
        map.put("Петров", "Петруччо");
        map.put("Оля", "Коля");

        return map;
    }

public static void removeTheFirstNameDuplicates(HashMap<String, String> map)
    {
        HashMap<String, String> map2 = new HashMap<String, String>(map); //дубликат map
        HashMap<String, String> map3 = new HashMap<String, String>(map); //дубликат map

        for (Map.Entry<String, String> pair : map2.entrySet())
        {
            map3.remove(pair.getKey());

            if (map3.containsValue(pair.getValue()))
            {
                removeItemFromMapByValue(map, pair.getValue());
            }
        }
    }


В коллекции map значения никак не упорядочены, но всё равно порядок какой-то должен быть произвольный, они же(значения) не плавают там как рыбы в океане, динамично перемещаясь по ячейкам памяти. Т.е. если в map ключ-значение «Иванов» — «Петя» первое, то и в дубликате map2 оно будет тоже первым. Верно?
map3.remove(pair.getKey()); — удаляем из map3 первую пару значений
if (map3.containsValue(pair.getValue())) — по логике вещей при одном прохождении цикла for get.Key и getValue для все map(2)(3) будет первое значение, допустим «Сидоров». Такого что б getValue для map2 и getValue для map3 вызывал разные значение быть не может, при условии что map3 и map2 копии map?
  • ,

Часто задаваемые на собеседованиях вопросы по классам коллекциям в Java (Часть 1).

Без сомнения, коллекции в Java это крайне важная область, и вопросы по коллекциям будут задавать на собеседованиях как новичкам так и опытным программистам. Тема настолько обширна, что практически невозможно покрыть ее целиком. И все же, основываясь на моих предыдущих собеседованиях, я попробую перечислить как можно больше ХОРОШИХ вопросов, к которым вы должны быть готовы.
Вопросы будут как сложные так и простые, так что если вопрос кажется вам слишком примитивным — не забывайте что он отлично подойдет менее опытному программисту.
  • ,

Часто задаваемые на собеседованиях вопросы по классам коллекциям в Java (Часть 2).

  • ,

level08.lesson11.home01

Set из котов
1. Внутри класса Solution создать public static класс кот – Cat.
2. Реализовать метод createCats, он должен создавать множество (Set) котов и добавлять в него 3 кота.
3. В методе main удалите одного кота из Set cats.
4. Реализовать метод printCats, он должен вывести на экран всех котов, которые остались во множестве. Каждый кот с новой строки.
То ли я что-то не понимаю, то ли жестко заклинило… Но не могу понять за что зацепиться. Накодил только что-то подобное:

package com.javarush.test.level08.lesson11.home01;

import java.util.HashSet;
import java.util.Set;

public class Solution
{
    public static void main(String[] args)
    {
        Set<Cat> cats = createCats();

        //Написать тут ваш код. step 3 - пункт 3

        for (Cat m : cats)
        {
            if (m.equals(cat2)) cats.remove(m); //тут не правильно... Но не имею никаких идей как правильно указать через psvm то, что я хочу удалить определенный объект который был создан и записан в другом методе.
        }

        printCats(cats);
    }

    public static Set<Cat> createCats()
    {
        //Написать тут ваш код. step 2 - пункт 2

        Set<Cat> cats = new HashSet<Cat>();  //создал множество
        Cat cat = new Cat();  //создал объекты-котов
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();

        cats.add(cat); // добавил объекты в множество
        cats.add(cat1);
        cats.add(cat2);
        return cats;
    }

    public static void printCats(Set<Cat> cats)
    {
        // step 4 - пункт 4

        for (Cat p : cats)
        {
            System.out.println(p);
        }
    }

    // step 1 - пункт 1

    public static class Cat  // ничего не добавлял тут внутри, поскольку сами свойства класса не упоминаются в условии задачи, только "кот" как сам объект
    {
        
    }
}