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
который выполнял бы чужой метод над каждым элементом коллекции.
[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
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
По моему это самое слабое место Java. Хотя один перец вроде попытался чего-то сделать
http://weblogs.java.net/blog/alexwinsto ... pes_1.html
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]
в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь 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]
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Можно воспользоваться декоратором из java.util.Collections.unmodifiableList()Oscar писал(а):общая идея такова:
в мире есть слишком много людей с не совсем ровными руками ...
и если я буду отдавать из своего метода весь ArrayList, то они его "испортят" (могут изменить без моего ведома)
2B OR NOT(2B) = FF
- 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]
[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]
-
- Сообщения: 60
- Зарегистрирован: 06 дек 2004, 10:46
- Откуда: Kyiv, Ukraine
- Контактная информация:
Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Absurd абсолютно прав - рефлекшн - штука жутко медленная.
Absurd абсолютно прав - рефлекшн - штука жутко медленная.
... She gave me something, it was a mushroom...
-
- Сообщения: 1228
- Зарегистрирован: 26 фев 2004, 13:24
- Откуда: Pietari, Venäjä
- Контактная информация:
Если сделать getArrayList(), то приватность не спасет - через полученную ссылку с массивом можно делать все, что угодно. Можно, правда, возвращать не ссылку на приватное поле, а клон этого поля. Или декоратор, который не допускает модификаций.Chester писал(а):Вот чего-то я не совсем понял сути вопроса, но почему нельзя просто внутри класса приватно спрятать ArrayList и выставить наружу только необходимые public методы?
Работал с немецким проектом, где немцы боялись анонимных классов, и использовали рефлекшен подобным образом =). Лучше не вспоминать.Chester писал(а):Absurd абсолютно прав - рефлекшн - штука жутко медленная.
2B OR NOT(2B) = FF
- Oscar
- Сообщения: 963
- Зарегистрирован: 29 май 2004, 13:44
- Откуда: Мюнхен (рожден в Киеве)
- Контактная информация:
Спасибо, не знал, честно говоря даже не задумывался об этом.Absurd писал(а):Только прошу не забывать, что вызов метода через java.lang.reflect.Method медленние обычного вызова виртуальной функции минимум в два раза.
Это-то можно, но для того, чтобы "пробежать" по всем элементам списка, нужен какой-то способ. Как я писал в начале - либо это Iterator, либо через классы - Visitor_ы.Chester писал(а):спрятать ArrayList и выставить наружу только необходимые public методы?
То есть я правильно тебя понял, что нормальные люди делают это именно через анонимные классы, типа "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 :-)