I am trying to apply a method to an array of arrays through a for loop.
Unfortunately where I have inserted my array of arrays inside the checkGuess method, I am getting the error 'Local variable x defined in an enclosing scope must be final or effectively final'. I'm a little new to Java so I'm not sure what I'm doing wrong... any help would be greatly appreciated.
for(int x = 0; x < columns.length; x++){
columns[x][y].addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
checkGuess(columns[x][y]);
}
});
if(x>4 && y<5){
y++;
x=-1;
}
}
Additional info:
The array of arrays contains JButtons.
The method checkGuess() takes a JButton as an argument as so:
checkGuess(JButton guess){
}
In Java, variables that are used in an anonymous class must be final (or in Java 8, effectively final - essentially the same thing, just without the explicit final modifier). As for why this is, Jon Skeet has a very nice answer to this here.
One method of correcting your code is simply to assign x to a final reference, as shown below:
for (int x = 0; x < columns.length; x++) {
final int copy = x;
columns[x][y].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
checkGuess(columns[copy][y]);
}
});
}
ActionListener is an inner anonymous class and it doesn't know what 'x' is when it tries to read it when passing the array of arrays to the function checkGuess().
Untested, but this might work:
for(int x = 0; x < columns.length; x++){
columns[x][y].addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
checkGuess(this);
}
});
if(x>4 && y<5){
y++;
x=-1;
}
}
If not, you would need to find out how to pass x into the class.
I believe "this" will reference the parent of the class, which should be 'columns[x][y]. I could be wrong though.
Related
I've built a 2d array of ImageViews, and I want to be able to print out the indices of the ImageView when I click it (and use that information to change the pictures).
I've got the following code right now, but I don't know how to get it to print the x and y values of its location in the 2d array.
ImageView[][] mainGrid = new ImageView[8][8];
...
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
mainGrid[x][y] = new ImageView(image);
mainGrid[x][y].setOnMouseClicked(createMouseHandler());
}
}
...
private EventHandler<? super MouseEvent> createMouseHandler() {
return event -> {
System.out.println("Clicked");
}
}
Any help is greatly appreciated! Thank you!
The most general solution to this problem is to use the getProperties() method of the Node class. You can use that to store any user information in a node you like and then later retrieve that if you need it. In your case store the indices and then retrieve them in your mouse handler.
I have the following function in Solidity which takes as arguments 2 arrays, an array of shareholder addresses and an array of their stakes. I'm keeping an array of shareholders in storage, together with a map to their stakes.
If the updated array is the same size, it's simple, just overwrite each position with the new values. If they are different sizes however, I first go through the entire array and delete each element, and then insert the new ones. I feel this is not very efficient and it could be done better.
PS: I am a complete beginner to Solidity and this is my first contract, so please feel free to let me know if I'm doing anything stupid or inefficiently.
Thanks !
function setShareholders(address[] _shareholders, uint256[] _stakes) public onlyCEO {
require(_shareholders.length > 0);
require(_shareholders.length == _stakes.length);
uint256 accummulator = 0;
for(uint8 x = 0; x < _stakes.length; x++){
require(_addressNotNull(_shareholders[x]));
require(_stakes[x] > 0 && _stakes[x] <= 100);
accummulator = SafeMath.add(accummulator, _stakes[x]);
}
if(accummulator == 100){ // stakes need to add up to 100%
_setShareholders(_shareholders, _stakes);
}
}
function _setShareholders(address[] _shareholders, uint256[] _stakes) private {
if(_shareholders.length == shareholders.length){
for(uint8 x = 0; x < shareholders.length; x++) {
shareholders[x] = _shareholders[x];
shareholderToStake[_shareholders[x]] = _stakes[x];
}
}
else {
for(x = 0; x < shareholders.length; x++) {
delete shareholders[x];
shareholders.length--;
delete shareholderToStake[shareholders[x]];
}
for(x = 0; x < _shareholders.length; x++) {
shareholders.push(_shareholders[x]);
shareholderToStake[_shareholders[x]] = _stakes[x];
}
}
}
In theory, this would work...unfortunately in solidity, managing arrays is a costly nightmare. Doing any array manipulation, on not just one but 2 arrays, is not recommended at all.
You could keep your array of shareholders...but from there, I'd recommend creating a mapping of address->structure. This way you can loop through your mapped structure and contain all necessary data within that.
So something like this for your refactor:
address[] public shareholders;
struct ShareHolder {
uint stake;
// ...other awesome data here
}
mapping (address => ShareHolder) public shareholderData;
This way, you have your shareholders list. And you can directly access a shareholder with shareholderData[<SHAREHOLDER ADDRESS>].
Is there a way to continue the most outer loop from the most nested one in ABAP?
Example in Java. There is a construct in this language using labels (most people do not know of it anyway) which allows me to continue the most outer loop from the nested one.
public class NestedLoopContinue {
public static void main(String[] args) {
label1: for (int i = 0; i < 5; i++) {
for (int j = 0; j < 2; j++) {
if (i == 3) {
continue label1;
}
}
System.out.println(i + 1);
}
}
}
This outputs
1
2
3
5
Now, how can I do it in ABAP in a smart way? One solution would be to use TRY. ENDTRY. block but it is rather a hacking one. Any other ideas?
DATA: l_outer_counter TYPE i.
DO 5 TIMES.
l_outer_counter = sy-index.
TRY.
DO 2 TIMES.
IF l_outer_counter = 4.
RAISE EXCEPTION TYPE cx_abap_random.
ENDIF.
ENDDO.
WRITE / l_outer_counter.
CATCH cx_abap_random.
CONTINUE.
ENDTRY.
ENDDO.
Or maybe there is a way to tell whether the DO. ENDO. ended with an EXIT statement (without introducing an own variable of course, like SYST global variable)?
DATA: l_outer_counter TYPE i.
DO 5 TIMES.
l_outer_counter = sy-index.
DO 2 TIMES.
IF l_outer_counter = 4.
EXIT.
ENDIF.
ENDDO.
IF sy-last_loop_ended_with_exit = abap_true. "???
CONTINUE.
ENDIF.
WRITE / l_outer_counter.
ENDDO.
I don't know of an ABAP-specific solution, but I've used a general programming solution to handle this before; simply use a boolean and check at the end of the inner loop whether or not to continue.
In Java:
public class NestedLoopContinue
{
public static void main(String[] args)
{
for (int i = 0; i < 5; i++)
{
boolean earlyBreak = false;
for (int j = 0; j < 2; j++)
{
if (i == 3)
{
earlyBreak = true;
break;
}
}
if (earlyBreak)
{
continue;
}
System.out.println(i + 1);
}
}
}
And in ABAP:
DATA: l_outer_counter type i,
early_break type FLAG.
DO 5 TIMES.
l_outer_counter = sy-index.
DO 2 TIMES.
IF l_outer_counter = 4.
early_break = ABAP_TRUE.
EXIT.
ENDIF.
ENDDO.
IF early_break = ABAP_TRUE.
CLEAR early_break.
CONTINUE.
ENDIF.
WRITE / l_outer_counter.
ENDDO.
I've read that the reason label-based breaks exist in Java in the first place is because GOTO statements explicitly do not, and the case covered by label-based break was one of the few "good" uses of GOTO that the team wanted to maintain.
In general, though, this is a very awkward construction. Is there no potential way to refactor your code (perhaps swapping the inner-ness of the loops) to remove the need for this in the first place?
When working with nested loops, I often find the best way to improve readability, and avoid using more unusual approaches (such as breaking to a label, which is not only controversial because of its goto-like nature, but also reduces readability because a lot of people are not familiar with them) is to extract the inner loop into a separate function. I do not know how this is done in ABAP, but the refactored Java equivalent would be:
public class NestedLoopContinue {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
NestedLoopContinue.innerLoop(i)
}
}
static void innerLoop(int i) {
for (int j = 0; j < 2; j++) {
if (i == 3) {
return;
}
}
System.out.println(i + 1);
}
}
I would argue that in this example, this actually becomes less readable because it is harder to follow the logic across the two methods. However, if this was a real-world example (where the methods and variables had some actual meanings and appropriate names to go with them), then the result of extracting the inner loop into a separate method would be more readable than using a label.
Based on the robjohncox answer, the ABAP code might look like this.
CLASS lcl_nested_loop_continue DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS:
main.
PRIVATE SECTION.
CLASS-METHODS:
inner_loop
IMPORTING
i_index TYPE i.
ENDCLASS.
CLASS lcl_nested_loop_continue IMPLEMENTATION.
METHOD main.
DO 5 TIMES.
lcl_nested_loop_continue=>inner_loop( sy-index ).
ENDDO.
ENDMETHOD.
METHOD inner_loop.
DO 2 TIMES.
IF i_index = 4.
RETURN.
ENDIF.
ENDDO.
WRITE / i_index.
ENDMETHOD.
ENDCLASS.
I have an error when trying to run this program. This is not the entire program just the few details I think where the problem is. The error points out
if(board[randSpace].isEmpty()) and
cl.makeChutes(5);"
Error is :
"Exception in thread "main" java.lang.NullPointerException
at ChutesAndLadders.makeChutes(ChutesAndLadders.java:29)
at ChutesAndLadders.main(ChutesAndLadders.java:67)"
This is my program:
import java.util.Random;
public class ChutesAndLadders{
Cell [] board = new Cell [100];
Random rand = new Random ();
public int chutes, ladders;
public void makeChutes (int a ){
int makeChutes = a;
for (int i = 0; i < a; i++){
int randSpace = rand.nextInt(99);
if(board[randSpace].isEmpty())
board[randSpace] = new Cell (-10,"C");
else
i--;
}
}
public static void main(String[] args) {
// Create an instance of ChutesAndLadders
ChutesAndLadders cl = new ChutesAndLadders(10,10);
// Randomly place 5 more chutes and 5 more ladders
cl.makeChutes(5);
cl.makeLadders(5);
Here is my isEmpty:
public boolean isEmpty(){
for(int i = 0; i < board.length; i++)
{
if (board[i].isEmpty())
return true;
}
return false;
}
I could be entirely wrong on my coding. I'm still learning so please be patient. Thank you!
Following on what Dewfy said, board is an array of Cell objects. That means it is a placeholder for Cell objects --a bunch of nulls waiting to be replaced by a Cell.
If say, the object at position 1 (board[1]) has not been assigned a Cell object (i.e. you haven't issued a command like board[1]=new Cell() or something like that) then board[1] is null. Therefore if you were to ask board[1].isEmpty() you would get a NullPointerException because you are trying to call a method on a null object.
Now, your error is likely to come from board[randSpace] being null. So, the question is: does it contain a Cell object? Have you initialized your array with Cell objects?
One way to check this would be to say:
if (board[randSpace]==null || board[randSpace].isEmpty()) .....
Problem appears with this line:
if(board[randSpace].isEmpty())
so it is supposed that obect at randSpace already exists, if not you create object (Cell). But object is not yet created, how you can ask it if null isEmpty(). Just check against null first
I have included my source code draft below. I would appreciate any input on what I'm doing incorrectly. I'm not sure my syntax is correct... Also, I did find an example on Cramster; but I'm not sure that the example implemented the "subscript" as directed (please point it out if I am wrong in this) by the instructions. I also think that the "for" loop is rather repetitive since it appears that it's establishing the same thing that the subscript is supposed to establish... This code is in response to the following assignment:
"Write a program in which you declare an array of five integers and store five values in
the array. Write a try block in which you place a loop that attempts to access each
element of the array, incrementing a subscript from 0 to 10. Create a catch block that
catches the eventual IndexOutOfRangeException; within the block, display “Now
you’ve gone too far.” on the screen. Save the file as GoTooFar.cs."
Microsoft® Visual C#® 2008, An Introduction to Object-Oriented Programming, 3e, Joyce Farrell
My source code with errors:
using System;
namespace Further
{
public class GoTooFar
{
public static void Main()
{
private static int[] fiveIntArray = {1, 2, 3, 4, 5};
//private static int CUTOFF = 11;
int subscript;
int rate;
try
{
//bool further;
//public static int DetermineArray(int further)
for(int x = 0; x < 10; x++)
if(further < 11)
throw new IndexOutofRangeException("Now you've gone too far.");
subscript = 0;
else
subscript = 10;
rate = fiveIntArray[subscript];
return rate;
}
catch(IndexOutOfRangeException e)
{
throw;
Console.WriteLine(e.StackTrace);
//Console.WriteLine("Now you've gone too far.");
//return e;
}
}
}
}
//The example I found on Cramster.com:
using System;
namespace Console2
{
class Class1
{
static void Main(string[] args)
{
int[] numbers = new int[5] {1, 2, 3, 4, 5};
try
{
for(int i=0;i<10;i++)
if(i>5)
throw new IndexOutOfRangeException("Now you’ve gone too far.");
}
catch(IndexOutOfRangeException e)
{
throw;
}
}//end ma...
}
}
You're not supposed to throw an exception, just catch the one the runtime throws. There are several other issues:
You are declaring a field inside a method. Just drop the private static.
Only the if/else was in the for loop, but you clearly intend the access to be too. I prefer to always use curly braces, but that's subjective.
You apparently intend to return every iteration, which doesn't make sense.
It can be as simple as:
public static void Main()
{
int[] fiveIntArray = {1, 2, 3, 4, 5};
try
{
for(int x = 0; x < 10; x++)
{
int rate = fiveIntArray[x];
}
}
catch(IndexOutOfRangeException e)
{
Console.WriteLine("Now you've gone too far.");
}
}
Note, we don't actually use rate. It's just there so it will be a valid statement.