2016-08-17 3 views
1

Я создаю симулятор, но для простоты это «игра». Таким образом, он имеет функцию render() и update(). Я пытался практиковать лямбда-выражения в течение лета, но я, похоже, не могу склонить голову вокруг выражения лямбда другого выражения лямбды. Я, наверное, говорю это неправильно, но то, что я пытаюсь сделать, это начать два потока, один что петли рендеринга, и еще что петли обновления. Я могу получить это далеко:Java 8 Возможное двойное выражение Lambda

void render() { 
    //draw entities, etc. 
} 
void update() { 
    //update player/enemies, etc. 
} 

public GameFrame() { 
    /* init stuff */ 
    Thread updateThread = new Thread(this::update); 
    Thread renderThread = new Thread(this::render); 
} 

Это не то, что я хочу, потому что это работает только обновление и сделать один раз, таким образом, это только две нити, одна , делающего раз и один , который обновляет раз (нет цикла). Я хочу создать функцию, которая что-то делает в соответствии с:

public void loop(Supplier< /*?*/ > arg) { 
    long startTime; 
    while(running) { 
     startTime = System.currentTimeMillis(); 
     supplier.get(arg) // <- not sure about this either 
     try { 
      long sleepTime = 1000/FPS - (System.currentTimeMillis() - startTime); 
      if(sleepTime > 0) 
       Thread.sleep(sleepTime); 
     } catch(InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Тогда я бы назвал функцию следующим образом:

loop(this::update); 

Я считаю, что это вызвало бы прилагаемое функцию петли, таким образом, я попытался:

Thread updateThread = new Thread(this::loop(this::update)); 

Или даже что-то вроде этого:

new Thread(() -> loop(this::update)).start(); 

Я знаю, что могу просто сделать мой визуализации функция while while и моя функция обновления while, просто скопировав код «void loop (поставщик arg)» в каждую часть, но я хотел посмотреть, смогу ли я сделать это так или иначе.

Мне не нужен точный ответ, мне просто хотелось бы, чтобы некоторые указания касались того, о чем я не думаю, о том, что я думаю о неправильном. Я не смог добиться большого прогресса, прочитав лямбда-выражения на оракуле.

+3

Ваша последняя идея в порядке, но метод loop() должен принимать аргумент Runnable as, а не поставщик, поскольку вы хотите выполнить функцию, которая не принимает аргументов и ничего не возвращает, и это то, что Runnable. И поэтому он должен вызывать run() на этой runnable, на каждой итерации. –

+4

Первое, почему вы думаете о «петле сна» вместо использования таймера? – RealSkeptic

+2

В качестве альтернативы использованию голых металлических нитей вы также можете использовать ExecutorServices и продолжать отправлять задания в них. Это не поможет с lambdas, но это упростит тестирование (потому что вы можете легко заменить многопоточную службу-исполнителя исполнителем «do-it-in-the-current-thread». – GhostCat

ответ

1

Конструктор Thread принимает Runnable, и это то, что вы хотите выполнить повторно. Поэтому вам не нужно Supplier как тип параметра для loop, но Runnable.

public void loop(Runnable arg) { 
    long startTime; 
    while(running) { 
     startTime = System.currentTimeMillis(); 
     arg.run(); 
     try { 
      long sleepTime = 1000/FPS - (System.currentTimeMillis() - startTime); 
      if(sleepTime > 0) 
       Thread.sleep(sleepTime); 
     } catch(InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Обратите внимание, что невозможно указать параметры с помощью ссылки на метод. Это недопустимый синтаксис:

this::loop(this::update) 

Заявление вы хотите нить, чтобы выполнить это:

loop(this::update); 

так что вам нужно использовать лямбда-выражения с этим утверждением в качестве органа в качестве параметра Thread конструктора:

Thread updateThread = new Thread(() -> loop(this::update)); 

Обратите внимание, что ScheduledExecutorService предоставляет вид планирования, который вы реализуете здесь.

+0

вы бы знали, почему Java не позволяет: 'this :: loop (this :: update)?? Я заметил, что если функция имеет параметр, я должен ссылаться на нее как'() -> doFoo (arg) '. Почему это так? –

+0

a) вам нужен целевой тип для ссылки на метод для работы (для 'this :: loop' нет ни одного) и b) даже если у вас был целевой тип java, не поддерживает currying как язык, поэтому вам нужно реализовать его по-разному. – fabian

Смежные вопросы