Java / Groovy: создать и прочитать список из двух объектов

#java #groovy

#java #groovy

Вопрос:

Как мне определить список из двух объектов (Foo, Bar) и выполнить итерацию по нему?

Что я пробовал:

 // create
def fooBar = new ArrayList<Foo, Bar>()
fooBar.add(new Foo())
fooBar.add(new Bar())
fooBar.add(new Foo()) // << shouldn't be allowed or overwrite first foo

def fooBars = new ArrayList<List<Foo, Bar>>()
fooBars << fooBar

// read
fooBars.each { fooBar ->
  def foo = fooBar[0]
  def bar = fooBar[1]
  // do something with foo and bar
}
  

Чего я хочу:

 // pseudo code
def fooBar = new ???<Foo, Bar>()
fooBar.set(new Foo())
fooBar.set(new Bar())

def fooBars = new ArrayList<???>()
fooBars << fooBar

fooBars.each { fooBar ->
  def foo = fooBar[???] // 0, 'foo', ..?
  def bar = fooBar[???]
  // do something with foo and bar
}
  

Если создание моего собственного класса FooBar является решением, я в порядке, я просто надеюсь, что есть более простое решение.

Комментарии:

1. Вы могли бы попробовать new AbstractMap.SimpleEntry<Foo, Bar>(...)

2. Неясно, что именно вы пытаетесь сделать. Вы пытаетесь создать список, в котором каждый элемент списка является либо Foo, либо Bar? Если это так, то вы хотите ArrayList<Object> . Похоже, вы также можете пытаться создать список пар Foo и Bars, и в этом случае вам нужно будет либо использовать какой-то Pair<T1, T2> класс, указанный где-то в какой-то библиотеке, либо написать свой собственный, а затем составить из этого список.

3. @user3030010 Как я понял, OP хочет список ровно из 2 элементов: один Foo и один Bar. Другими словами, кортеж / пара.

4. @Klitos Kyriacou: Да @user3030010: Я привел плохой пример, вместо Foo и Bar рассмотрим экземпляр File и FileReader , который имеет смысл только в комбинации / как пара.

Ответ №1:

В Groovy есть понятие кортежей.

 def tuple = new Tuple('one', 1)
def (String a, Integer b) = tuple
println a
println b
  

или альтернативно

 def doSomething(String s, Integer i) {
  println s
  println i
}
doSomething(tuple)
  

или альтернативно

 def doSomething(Tuple t) {
  println t[0]
  println t[1]
}
doSomething(tuple)
  

затем вы можете сделать

 def tuples = [ ] << tuple << tuple
tuples.each { doSomething(it) }
  

Комментарии:

1. И если вам нужны обобщения, есть Tuple2 , т.Е.: new Tuple2<Foo, Bar>(foo, bar)

2. Как выглядит этот список объектов.. выглядит как просто кортеж, с каких это пор кортеж — это список кортежей? Вопрос четко задает, как создать список, содержащий два объекта, каждый объект в списке — это два объекта, а не один объект из двух элементов.

3. @AistisTaraskevicius В первой части моего ответа говорится о кортежах как способе хранения «объектных» данных, поскольку в Groovy есть хорошие абстракции, как показано в моих примерах. Затем в последней части показано, как вы можете составить список кортежей (def tuples = [ ] << tuple << кортеж) и выполнять итерации по ним (tuples. каждый {doSomething(это) }).

Ответ №2:

Рассмотрим расширение Groovy. Например:

 class Foo {}
class Bar {}

def fooBar = new Expando()
fooBar."foo" = new Foo()
fooBar."bar" = new Bar()

def fooBars = []
fooBars << fooBar

fooBars.each { item  ->
    def foo = item."foo"
    def bar = item."bar"

    assert foo instanceof Foo
    assert bar instanceof Bar
}
  

Ответ №3:

Почему бы просто не использовать список списков? Каждый элемент списка может быть двухэлементным списком, содержащим Foo и Bar экземпляры в таком порядке.

Для дополнительной безопасности при построении каждого двухэлементного списка Foo / Bar напишите вспомогательный метод, который проверяется на тип и возвращает неизменяемый список, чтобы предотвратить вмешательство после построения.

 @TypeChecked
def makeFooBar(Foo foo, Bar bar) { 
    [foo, bar].asImmutable() 
}

def fooBars = [] 

// some code to populate the list...
fooBars << makeFooBar(new Foo(), new Bar())

// iterate and do something with each foo/bar pair
fooBars.each { fooBar ->
  def (foo, bar) = fooBar

}
  

Одна из областей, небезопасных для типов, — это fooBars список, который может быть заполнен другими типами объектов. Но если вы хотите такую степень безопасности типов, то, возможно, вам следует рассмотреть совсем другой язык.

Комментарии:

1. Спасибо за ваш ответ. Что вы имеете в виду, говоря «рассмотреть другой язык»? (Кстати, я родом из мира PHP) 🙂

2. Я просто имел в виду, что если вы хотите использовать общие термины и чтобы они что-то значили, вам следует рассмотреть Java вместо Groovy. Groovy, по умолчанию, строго не учитывает универсальные подписи; он с радостью выполнит код List<Integer> list = ['hi', 'there'] . Но, на мой взгляд, лучший способ справиться с этой слабостью — принять подход Groovy и написать свой код как def list = ['hi', 'there'] . В целом, однако, если вы подходите с точки зрения PHP, я думаю, Groovy вам хорошо подойдет.

Ответ №4:

Почему никто не предложил карту?

 def x = [:]
x['foo'] = new Bar()
  

Кажется, это немного умнее, чем список кортежей.