Collections forAll

Модератор: Absurd

Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

хочется запрятать ArrayList в класс, так чтобы был виден лишь итератор forAll,
который выполнял бы чужой метод над каждым элементом коллекции.

[syntax="java"]class Test {

private ArrayList<Integer> test;

public Test() {
test = new ArrayList<Integer>();
}

public void add(int i) {
test.add(i);
}

public void forAll(Method method) {

for(int i : test) {
method(i);
}
}

}[/syntax]

не будет идей, как это можно реализовать?

есть такой вариант:

[syntax="java"] public void forAllNodes(Object object, String name) {

Method method = null;

try {
method = object.getClass().getMethod(name, new Class[]{Node.class});
} catch (Exception e) {
e.printStackTrace();
}

for(int i : test) {
try {
method.invoke(object, new Object[]{i});
} catch (Exception e) {
e.printStackTrace();
}
}
}[/syntax]

но имя метода передаётся, как String и теряется проверка компилятором.


Может есть способ передавать что-то типа thisMethod, как передаётся this от класса?

есть другой вариант:

[syntax="java"] public abstract class ForAll {
protected void forAll() {
for(int i : test) {
forElement(i);
}
}

protected abstract void forElement(int i);
}

class Print extends ForAll {
protected void forElement(int i) {
System.out.println(i);
}
}[/syntax]

но тогда прийдётся в других классах создавать inner-классы вместо методов.

оба варианта мне не нравятся, хотелось бы узнать, как (можно ли) такое реализовать?

---

class ForAll - inner class Test
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

По моему это самое слабое место Java. Хотя один перец вроде попытался чего-то сделать

http://weblogs.java.net/blog/alexwinsto ... pes_1.html
2B OR NOT(2B) = FF
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

общая идея такова:

в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь ArrayList, то они его "испортят" (могут изменить без моего ведома)

можно, конечно, отдавать просто итератор ... это вариант ...

[syntax="java"]public Iterator<Integer> getTestIterator() {
return test.iterator();
}[/syntax]

но тут есть две проблемы:

1. Iterator работает немного медленнее, чем пробег по ArrayList (c) SUN
2. написанный код будет не так изящен :-)

[syntax="java"]for(int i : test) {
doSomething(i);
}[/syntax]

[syntax="java"]for(Iterator<Integer> iter = test.iterator(); i.hasNext() {
int i = iter.next();
doSomething(i);
}[/syntax]
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Oscar писал(а):общая идея такова:

в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь ArrayList, то они его "испортят" (могут изменить без моего ведома)
Можно воспользоваться декоратором из java.util.Collections.unmodifiableList()
2B OR NOT(2B) = FF
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

Absurd, спасибо! это весьма хорошая идея!

правда компилятор этого всё равно не отловит ....
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

Наконец-то добрался до ссылки на метод:

[syntax="java"]import java.lang.reflect.Method;

public class Test {

private Container container;

public Test() {
container = new Container();
container.add(1);
container.add(2);
}

public Method print(Object o) {
if (o == null) {
class EnclosedClass{}
return EnclosedClass.class.getEnclosingMethod();
}

System.out.println(o);

return null;
}

public void printAll() {
container.forAllNumbers(this, print(null));
}

public static void main(String[] args) {
Test test = new Test();
test.printAll();
}

}[/syntax]


ну и вот класс с пробегом forAll :

[syntax="java"]import java.lang.reflect.Method;
import java.util.ArrayList;

public class Container {

private ArrayList<Integer> numbers;

public Container() {
numbers = new ArrayList<Integer>();
}

public void add(int i) {
numbers.add(i);
}

public void forAllNumbers(Object object, Method method) {
for(Object o : numbers) {
try {
method.invoke(object, o);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}[/syntax]
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Только прошу не забывать, что вызов метода через java.lang.reflect.Method медленние обычного вызова виртуальной функции минимум в два раза.
2B OR NOT(2B) = FF
Chester
Сообщения: 60
Зарегистрирован: 06 дек 2004, 10:46
Откуда: Kyiv, Ukraine
Контактная информация:

Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Absurd абсолютно прав - рефлекшн - штука жутко медленная.
... She gave me something, it was a mushroom...
Absurd
Сообщения: 1228
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

Chester писал(а):Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Если сделать getArrayList(), то приватность не спасет - через полученную ссылку с массивом можно делать все, что угодно. Можно, правда, возвращать не ссылку на приватное поле, а клон этого поля. Или декоратор, который не допускает модификаций.
Chester писал(а):Absurd абсолютно прав - рефлекшн - штука жутко медленная.
Работал с немецким проектом, где немцы боялись анонимных классов, и использовали рефлекшен подобным образом =). Лучше не вспоминать.
2B OR NOT(2B) = FF
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

Absurd писал(а):Только прошу не забывать, что вызов метода через java.lang.reflect.Method медленние обычного вызова виртуальной функции минимум в два раза.
Спасибо, не знал, честно говоря даже не задумывался об этом.
Chester писал(а):спрятать ArrayList и выставить наружу только необходимые public методы?
Это-то можно, но для того, чтобы "пробежать" по всем элементам списка, нужен какой-то способ. Как я писал в начале - либо это Iterator, либо через классы - Visitor_ы.
&quot писал(а):Работал с немецким проектом, где немцы боялись анонимных классов, и использовали рефлекшен подобным образом =).
То есть я правильно тебя понял, что нормальные люди делают это именно через анонимные классы, типа "Print extends ForAll" ?


Всё дело в том, что в одной немецкой библиотеке (LEDA), правда на языке C, есть следующая конструкция:

[syntax="c"] node v;

forall_nodes(v,G)
if ( !reached[v] ) {
S = DFS(G,v,reached);
forall(w,S) compnum[w] = count;
count++;
}[/syntax]

( Примеры можно посмотреть тут )

И вот я ищу способ использовать синтаксис:

Код: Выделить всё

forall_something(x) {
   do_something_with(x);
}

Я не знаю даже как на Си это реализовать, а хотелось бы именно такое написать на Java :-)
Ответить