Страница 1 из 2
Collections forAll
Добавлено: 23 мар 2007, 14:52
Oscar
хочется запрятать 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
Re: Collections forAll
Добавлено: 23 мар 2007, 15:00
Absurd
По моему это самое слабое место Java. Хотя один перец вроде попытался чего-то сделать
http://weblogs.java.net/blog/alexwinsto ... pes_1.html
Re: Collections forAll
Добавлено: 23 мар 2007, 15:05
Oscar
общая идея такова:
в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь 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]
Re: Collections forAll
Добавлено: 23 мар 2007, 15:08
Absurd
Oscar писал(а):общая идея такова:
в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь ArrayList, то они его "испортят" (могут изменить без моего ведома)
Можно воспользоваться декоратором из java.util.Collections.unmodifiableList()
Re: Collections forAll
Добавлено: 23 мар 2007, 15:11
Oscar
Absurd, спасибо! это весьма хорошая идея!
правда компилятор этого всё равно не отловит ....
ссылка на метод
Добавлено: 23 мар 2007, 21:05
Oscar
Наконец-то добрался до ссылки на метод:
[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]
Re: Collections forAll
Добавлено: 24 мар 2007, 16:16
Absurd
Только прошу не забывать, что вызов метода через java.lang.reflect.Method медленние обычного вызова виртуальной функции минимум в два раза.
Re: Collections forAll
Добавлено: 26 мар 2007, 14:04
Chester
Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Absurd абсолютно прав - рефлекшн - штука жутко медленная.
Re: Collections forAll
Добавлено: 26 мар 2007, 15:12
Absurd
Chester писал(а):Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Если сделать getArrayList(), то приватность не спасет - через полученную ссылку с массивом можно делать все, что угодно. Можно, правда, возвращать не ссылку на приватное поле, а клон этого поля. Или декоратор, который не допускает модификаций.
Chester писал(а):Absurd абсолютно прав - рефлекшн - штука жутко медленная.
Работал с немецким проектом, где немцы боялись анонимных классов, и использовали рефлекшен подобным образом =). Лучше не вспоминать.
Re: Collections forAll
Добавлено: 26 мар 2007, 18:10
Oscar
Absurd писал(а):Только прошу не забывать, что вызов метода через java.lang.reflect.Method медленние обычного вызова виртуальной функции минимум в два раза.
Спасибо, не знал, честно говоря даже не задумывался об этом.
Chester писал(а):спрятать ArrayList и выставить наружу только необходимые public методы?
Это-то можно, но для того, чтобы "пробежать" по всем элементам списка, нужен какой-то способ. Как я писал в начале - либо это Iterator, либо через классы - Visitor_ы.
" писал(а):Работал с немецким проектом, где немцы боялись анонимных классов, и использовали рефлекшен подобным образом =).
То есть я правильно тебя понял, что нормальные люди делают это именно через анонимные классы, типа "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 :-)